4

I'm trying to copy some remote files to the local drive, in Java, using JCIFS. The remote machine is inside a domain. The local machine is not in a domain.

The following code works, but it's really slow (2 minutes for 700Kb... and I have many Mb...):

SmbFile remoteFile = new SmbFile("smb://...")
OutputStream os = new FileOutputStream("/path/to/local/file");
InputStream is = remoteFile.getInputStream();
int ch;
while ((ch = is.read()) != -1) {
    os.write(ch);
}
os.close();
is.close();

I think I could use SmbFile.copyTo(), but I don't know how to access the local file. If I write the following, I get a connection error:

localfile = new SmbFile("file:///path/to/localfile")

This question is related to How to copy file from smb share to local drive using jcifs in Java?

Community
  • 1
  • 1
user1922691
  • 119
  • 1
  • 2
  • 6

3 Answers3

5

You just need to make bigger buffer:

SmbFile remoteFile = new SmbFile("smb://...")
try(OutputStream os = new FileOutputStream("/path/to/local/file")){
try(InputStream is = remoteFile.getInputStream())
{
    int bufferSize = 5096;

    byte[] b = new byte[bufferSize];
    int noOfBytes = 0;
    while ((noOfBytes = is.read(b)) != -1) {
        os.write(b, 0, noOfBytes);
    }
}}

Here some test I've done with file 23 Mb, using mentioned code.

bufferSize = 1024 Elapsed time : 10.9587606066 sec

bufferSize = 4096 Elapsed time : 5.6239662951 sec

bufferSize = 5096 Elapsed time : 5.0798761245 sec

bufferSize = 5096 Elapsed time : 4.879439883 sec

bufferSize = 10240 Elapsed time : 4.0192989201 sec

bufferSize = 50240 Elapsed time : 3.8876541543 sec

bufferSize = 100240 Elapsed time : 3.742167582 sec

Jon Bates
  • 3,055
  • 2
  • 30
  • 48
maxmimko
  • 51
  • 1
  • 4
  • Its taking too much time to make InputStream and copy in destination file. I had 1KB file and it was taking more than 1 min to finish the activity. Is there any way to make it fast???? – Jaikrat Jul 25 '16 at 12:36
4

An SmbFile object can't be constructed except with a valid smb URL. See the Constructor Summary at http://jcifs.samba.org/src/docs/api/, along with the discussion about SmbFile URLs at the top.

SmbFile URLs have the following syntax: smb://[[[domain;]username[:password]@]server[:port]/[[share/[dir/]file]]][?[param=value[param2=value2[...]]]

So, if you really want to avoid using the input stream and use copyTo(), you'll have to have an SMB share on your local machine that you can point jCIFS to.

If your local machine is a Windows machine, there are some default shares that you might be able to access, like C$.

So, you could do something like:

NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication("domain", "username", "password") //or whatever authentication works on your local machine.
SmbFile myFile = new SmbFile("smb://localhost/C\$/path/to/localfile", auth)

Then you could use remoteFile.copyTo(myFile).

If you're not on a Windows host, you'll have to install Samba and setup a Samba share to connect to on your local machine... again, if you're absolutely bent on avoiding using inputStreams.

jonnybot
  • 2,435
  • 1
  • 32
  • 56
  • Notably, nagualjj indicates you can also use the format "C:/path/to/file", but I have had no success doing so. http://stackoverflow.com/questions/13359164/ – jonnybot Mar 01 '13 at 21:34
  • what is `remoteFile`?? – Jaikrat Jul 22 '16 at 10:33
  • From the original question, `remoteFile` is the SmbFile that the OP wants to copy to another location (in this case, `myFile`). – jonnybot Jul 22 '16 at 13:11
  • Oh yes, Thanks. I implemented this and its working. But its taking tooooo much time to make InputStream and copy. Is there any way to make it fast? – Jaikrat Jul 25 '16 at 12:34
4

As an alternative to @maxmimko 's answer, you could also make use of the Apache Commons IO library, and use IOUtils to handle the copying for you:

NtlmPasswordAuthentication creds = new NtlmPasswordAuthentication("domain", "user", "password");
SmbFile remoteFile = new SmbFile("smb://REMOTEHOST/SHARE/path/to/file", creds);
try (
    InputStream is = remoteFile.getInputStream();
    OutputStream os = new FileOutputStream("/path/to/local/file");
) {
    long bytesCopied = IOUtils.copyLarge(is, os);
} catch (IOException e) {
    // handle exception here; log it?
}
// streams are automatically closed by try-with-resources block

There is also IOUtils.copyLarge(InputStream is, OutputStream os, byte[] buffer), if you want to control the buffer size, but I've found the defaults used by IOUtils to be relatively good across the board.

Will
  • 3,500
  • 4
  • 30
  • 38