How to copy file from SMB share to local drive not in domain with JCIFS

StackOverflow https://stackoverflow.com/questions/14749434

  •  07-03-2022
  •  | 
  •  

سؤال

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?

هل كانت مفيدة؟

المحلول 2

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.

نصائح أخرى

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

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.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top