性能:使用 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 目录