性能:使用 JCIF 将文件复制到 Windows 网络非常慢

Posted

技术标签:

【中文标题】性能:使用 JCIF 将文件复制到 Windows 网络非常慢【英文标题】:Performance: Very slow file copying to Windows network using JCIF 【发布时间】:2013-08-09 18:43:22 【问题描述】:

我正在尝试将文件从本地计算机复制到 Windows 服务器中的共享文件夹。这是我使用的函数。

public static void copyFileUsingJcifs(final String domain, final String userName, final String password, final String sourcePath, final String destinationPath) throws IOException 
    final NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication(domain, userName, password);
    final SmbFile sFile = new SmbFile(destinationPath, auth);
    final SmbFileOutputStream smbFileOutputStream = new SmbFileOutputStream(sFile);
    final FileInputStream fileInputStream = new FileInputStream(new File(
            sourcePath));

    final byte[] buf = new byte[16384];
    int len;
    while ((len = fileInputStream.read(buf)) > 0) 
        smbFileOutputStream.write(buf, 0, len);
    
    fileInputStream.close();
    smbFileOutputStream.close();

我尝试了this 的答案,但对我不起作用。当我进行正常复制(复制和粘贴)时,一个 25MB 的文件最多只需要 8 分钟。但是当我使用我的 java 程序使用这个函数时,它需要超过 20 分钟。我怎样才能使这个复制更快? 提前致谢。

【问题讨论】:

可能有很多原因,缓冲区过度/不足运行(即写入需要更长的读取时间,减慢整个过程),网络延迟(未优化的数据包处理)和 API 开销。尝试使用byte 缓冲区,看看是否有任何改变 @MadProgrammer 我尝试了低缓冲区大小和一些大值。但是没有任何更好的性能变化。我正在使用 jcifs-1.3.17.jar 25 兆字节的 8 分钟对于 LAN 来说是相当慢的。你的环境是什么? @ThorbjørnRavnAndersen 我试图将文件复制到远程位置。在局域网中它工作正常。我在我的机器上使用 Windows 7。服务器在 Windows Server 2008 上运行。 听起来像小的缓冲区大小(无论是您的缓冲区还是 JCIF 中的传输缓冲区)。 【参考方案1】:

如果它可以帮助其他人...我有类似的问题,但在另一个方向(使用 JCIFS 缓慢复制到 Windows)。该问题已通过添加解决

-Djcifs.resolveOrder=DNS

到属性列表。 (BCAST 的default inclusion -- 向 255.255.255.255 发送 NetBios 名称查询广播 -- 是造成巨大延迟的原因。)

【讨论】:

只是为了添加到这个古老的线程 - 我们刚刚弹出了这个问题,这个选项帮助我们在追查根本原因时解决了这个问题。在我们的例子中,Samba 服务器赢得了本地 NetBIOS 选举并注册了一个不可路由的接口,导致 jCIFS 在尝试连接时挂起。【参考方案2】:

试试这个高度优化的函数,如果它仍然很慢然后增加代码中的缓冲区大小。就我而言,它将复制 48MB 文件的时间从 10 分钟缩短到 1 分钟

public static boolean createCopyOnNetwork(String domain,String username,String password,String src, String dest) throws Exception

    //FileInputStream in = null;
    SmbFileOutputStream out = null;
     BufferedInputStream inBuf = null;
    try
        //jcifs.Config.setProperty("jcifs.smb.client.disablePlainTextPasswords","true");
        NtlmPasswordAuthentication authentication = new NtlmPasswordAuthentication(domain,username,password); // replace with actual values  
        SmbFile file = new SmbFile(dest, authentication); // note the different format
        //in = new FileInputStream(src);
          inBuf = new BufferedInputStream(new FileInputStream(src));
        out = (SmbFileOutputStream)file.getOutputStream();
        byte[] buf = new byte[5242880];
        int len;
        while ((len = inBuf.read(buf)) > 0)
            out.write(buf, 0, len);
        
    
    catch(Exception ex)
    
        throw ex;
    
    finally
        try
            if(inBuf!=null)
                inBuf.close();
            if(out!=null)
                out.close();
        
        catch(Exception ex)
        
    
    System.out.print("\n File copied to destination");
        return true;

【讨论】:

【参考方案3】:

我注意到的是,jCIFS 为它读取的每个块做“一些事情”(afair jcifs.smb.SmbTransport.checkStatus(..)) - 即对于读入缓冲区的每个块。这意味着增加缓冲区大小可能真的会加快速度,尽管真正的问题仍然存在,但只发生 1 或 2 次,对整体时间的影响较小。

设置“jcifs.util.loglevel=3”有很大帮助,看看到底出了什么问题..

就我而言,最后我不得不设置“jcifs.smb.client.dfs.disabled=false”,因为“jcifs.resolveOrder=DNS”没有帮助..

【讨论】:

【参考方案4】:

我遇到了同样的问题。试过 -Djcifs.resolveOrder=DNS 没有运气。在阅读了一些缓冲区大小的 cmets 之后,我决定走极端并真正提高它。我知道我的传输速率至少应为 50mb/s,因此我将其转换为字节并将其设置为我的缓冲区,它按预期工作。

【讨论】:

您是否仅在 Java 客户端(如果您还记得...)上更改了 JCIFS 库中的缓冲区大小? 很遗憾,我不记得了。【参考方案5】:

有一些新的SMB java项目支持SMB2及以上,我想你可以试试看。

smbj - https://github.com/hierynomus/smbj -(Apache v2 许可证) jNQ - http://visualitynq.com/products/jnq-java-smb-client(商业许可)

请注意,SMB2 比 SMB1 (jCifs) 更好、更快、更安全

【讨论】:

【参考方案6】:

我比较了将大缓冲区写入共享文件夹中的文件所需的时间。 smbj 比 jcifs 快 10 倍以上!

【讨论】:

以上是关于性能:使用 JCIF 将文件复制到 Windows 网络非常慢的主要内容,如果未能解决你的问题,请参考以下文章

使用 Docker 文件中的 COPY 将文件夹从 Windows 主机操作系统复制到 Docker 映像中

将文件夹从 Android 应用程序复制到本地 Windows 目录

使用 vb.net 将文件从 Windows XP 复制到 Linux

windows命令之copy——复制文件或隐藏文件

如何将windows7里的文件复制到ubuntu中?

使用 Java 和 Samba JCIFS 访问文件