How to copy a file from an SMB share to a local drive and not to a domain with JCIFS
I am trying to copy some remote files to a local drive, in Java, using JCIFS. The remote machine is inside the domain. The local machine is not in the domain.
The following code works, but it is very slow (2 minutes for 700Kb ... and I have a lot of 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 can use SmbFile.copyTo (), but I dont 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 a file from smb resource to local disk using jcifs in Java?
source to share
The SmbFile object could not be created, except for a valid smb URL . See the Designer Summary at http://jcifs.samba.org/src/docs/api/ and also the discussion of 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 will have to have an SMB share on your local machine that you can point jCIFS to.
If your local computer is a Windows machine, there are some shared domains that you can access, like C $.
So, you can 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 can use remoteFile.copyTo(myFile)
.
If you are not on a Windows host, you will need to install Samba and configure Samba sharing to connect to your local machine ... again if you absolutely tend to avoid using inputStreams.
source to share
You just need to make a larger buffer:
SmbFile remoteFile = new SmbFile("smb://...")
OutputStream os = new FileOutputStream("/path/to/local/file");
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);
}
os.close();
is.close();
Here are some tests I did on a 23MB file using the code above.
bufferSize = 1024 Elapsed time: 10.9587606066 sec
bufferSize = 4096 Elapsed time: 5.6239662951 sec
bufferSize = 5096 Elapsed time: 5.0798761245 s
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
source to share
As an alternative to @ maxmimko answer, you can also use Apache Commons IO library and use IOUtils
to handle the copy 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 size of the buffer, but I found the defaults used to IOUtils
be relatively good across the board.
source to share