JCIFS: file retrieval is too slow to be usable

2019-01-17 12:27发布

问题:

I was just testing JCIFS for accessing Windows shares. It is very slow to the point of being completely unusable.

import jcifs.smb.*;

class First {
    public static void main(String[] args) throws Exception {
    try {
        //jcifs.Config.setProperty( "jcifs.netbios.wins", "192.168.1.220" );
        NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication("domain.com", "Administrator", "password");

        SmbFile f = new SmbFile("smb://10.17.15.12/Share/xml/file.xml", auth);
        SmbFileInputStream in = new SmbFileInputStream(f);
        byte[] b = new byte[8192];
        int n;
        while(( n = in.read( b )) > 0 ) {
        System.out.write( b, 0, n );
        }
    } catch (SmbException smbe) {
        System.err.println(smbe.getNtStatus());
        System.err.println(smbe.toString());
        System.err.println(smbe.getCause());
    }
    }
}

It takes very long time for initial output to come and subsequent reads are also very slow. Any ideas how to use it? Any alternatives by which I can write Java code to access the Windows shares in a portable way are also welcome

回答1:

I found somewhere that SmbFileInputStream doesn't do its own buffering and hence the reason for being slow. Wrapping SmbFileInputStream in a BufferedInputStream solved the problem.

 SmbFile sFile = new SmbFile(path, authentication);

 BufferedInputStream buf = new BufferedInputStream(new SmbFileInputStream(sFile));


回答2:

In my own case, pushing files TO a Windows share via JCIFS was too slow to be usable.

The solution turned out to be defining the property

-Djcifs.resolveOrder=DNS

The default inclusion of BCAST -- broadcasting a NetBIOS name query to 255.255.255.255 -- was needlessly resulting in a lengthy delay. (Link above de-framed from the top-level API docs.)



回答3:

What I noticed is that jCIFS does "something" (afair jcifs.smb.SmbTransport.checkStatus(..)) for every chunk it reads - i.e. for each chunk that is read into the buffer. That means using a BufferedInputStream might really speed things up, but the real problem still exists. It only doesn't occur as often as before and therefore has a lower impact on the overall time ..

It helps a lot to set "jcifs.util.loglevel=3" and have a look what's really wrong!

In my case I had to set "jcifs.smb.client.dfs.disabled=false" in the end, as "jcifs.resolveOrder=DNS" didn't help..



回答4:

If you can rely on "something else" to mount the share as a local directory for you, then reading files in the mounted share in Java should be portable.

Even if this is not a real solution, it would be worth trying this to see if you get a faster read rate. A significantly faster read rate might change your mind about the relative importance of portability. And if you don't get a significant speedup, then you'll know that JCIFS is not to blame ...



回答5:

Even with the existing suggestions I still found JCIFS too slow to stream videos over my local network. It seems to be do with the overhead per buffer read from the network, even reading into large buffers JCIFS itself had a limited buffer size which was the problem.

If you look in https://jcifs.samba.org/src/patches/ there's a patch, LargeReadWrite.patch. You'll need to apply the patch and rebuild the code to use it, but it made a big difference for me.



回答6:

The solution added by @Xolve0 worked for me as well. The buffer issue in the SmbFileInput is also present when trying to write files. I used the same BufferedInputStream(new SmbFileInputStream(sFile)) to make the time execution decrease from 90secs to less than a second for a plain text file.

A quick way to identify this specific issue would be to track the time between the opening of the JCIFS path and the write of the file itself.