如何使用 JCIFS 将文件从 SMB 共享复制到不在域中的本地驱动器

Posted

技术标签:

【中文标题】如何使用 JCIFS 将文件从 SMB 共享复制到不在域中的本地驱动器【英文标题】:How to copy file from SMB share to local drive not in domain with JCIFS 【发布时间】:2013-01-22 20:28:41 【问题描述】:

我正在尝试使用 JCIFS 将一些远程文件以 Java 复制到本地驱动器。 远程计算机位于域内。本地计算机不在域中。

以下代码有效,但它真的很慢(700Kb 需要 2 分钟...而且我有很多 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();

我想我可以使用 SmbFile.copyTo(),但我不知道如何访问本地文件。如果我编写以下内容,则会出现连接错误:

localfile = new SmbFile("file:///path/to/localfile")

此问题与How to copy file from smb share to local drive using jcifs in Java?有关

【问题讨论】:

【参考方案1】:

你只需要做更大的缓冲区:

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);
    

这里我使用提到的代码对 23 Mb 文件进行了一些测试。

bufferSize = 1024 经过时间:10.9587606066 秒

bufferSize = 4096 经过时间:5.6239662951 秒

bufferSize = 5096 经过时间:5.0798761245 秒

bufferSize = 5096 经过时间:4.879439883 秒

bufferSize = 10240 经过时间:4.0192989201 秒

bufferSize = 50240 经过时间:3.8876541543 秒

bufferSize = 100240 经过时间:3.742167582 秒

【讨论】:

制作 InputStream 并复制到目标文件需要太多时间。我有 1KB 的文件,完成活动需要超过 1 分钟。有什么办法让它快吗???【参考方案2】:

无法使用有效的 smb URL 构造 SmbFile 对象除了。请参阅http://jcifs.samba.org/src/docs/api/ 的构造函数摘要,以及顶部有关 SmbFile URL 的讨论。

SmbFile URL 具有以下语法: smb://[[[domain;]username[:password]@]server[:port]/[[share/[dir/]file]]][?[param=value[param2=value2[...] ]]

因此,如果您真的想避免使用输入流并使用 copyTo(),则必须在本地计算机上拥有一个可以将 jCIFS 指向的 SMB 共享。

如果您的本地计算机是 Windows 计算机,则您可能可以访问一些默认共享,例如 C$。

所以,你可以这样做:

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)

那么你可以使用remoteFile.copyTo(myFile)

如果您不在 Windows 主机上,则必须安装 Samba 并设置 Samba 共享以连接到您的本地计算机...再次,如果您绝对一心要避免使用 inputStreams。

【讨论】:

值得注意的是,nagualjj 表示您也可以使用格式“C:/path/to/file”,但我没有成功。 ***.com/questions/13359164 什么是remoteFile?? 从原始问题来看,remoteFile 是 OP 想要复制到另一个位置的 SmbFile(在本例中为 myFile)。 哦,是的,谢谢。我实现了这个及其工作。但是它花费了太多时间来制作 InputStream 和复制。有什么办法让它快点?【参考方案3】:

作为@maxmimko 答案的替代方案,您还可以使用 Apache Commons IO 库,并使用 IOUtils 为您处理复制:

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

还有IOUtils.copyLarge(InputStream is, OutputStream os, byte[] buffer),如果你想控制缓冲区大小,但我发现IOUtils使用的默认值总体上比较好。

【讨论】:

以上是关于如何使用 JCIFS 将文件从 SMB 共享复制到不在域中的本地驱动器的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 JCIFS 移动(而不是复制)文件?

使用 jcifs 将整个本地目录复制到 smb 共享?

使用最后一个 smb jcifs-ng jar 复制文件

JCIFS SmbException

使用 jcifs 读取文件的最简单方法

JCIFS jcifs.smb.SmbException:连接到系统的设备无法正常工作