首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >当文件几乎被下载时,Apache FTPClient无法检索它

当文件几乎被下载时,Apache FTPClient无法检索它
EN

Stack Overflow用户
提问于 2018-01-04 11:07:54
回答 2查看 2.1K关注 0票数 2

Apache的FTPClient无法下载FileZilla完美下载的文件。

基本上,在成功登录和列表之后,我要做的是下载一个特定的文件:

代码语言:javascript
复制
FTPClient client = new FTPClient();
client.setDataTimeout(20000);
client.setConnectTimeout(20000);
client.setBufferSize(65536);
//...
client.connect(host);
client.login(user, pswd);
// response validation
client.enterLocalPassiveMode();
// some listings with validations

InputStream in = new BufferedInputStream(client.retrieveFileStream(ftpFilePath), 16384);
// ...
byte[] buffer = new byte[8192];
while ((rd = in.read(buffer)) > 0) {
// .. reading the file and updating download progress

最后一行可以很容易地替换为FTPClient的文件下载,结果几乎相同,但是我们无法跟踪下载进度:

代码语言:javascript
复制
client.setControlKeepAliveTimeout(30);
client.retrieveFile(ftpFilePath, new org.apache.commons.io.output.NullOutputStream());

作为所有这些操作的结果,我可以看到文件正在下载,直到非常接近100%的内容,然后出现异常:

代码语言:javascript
复制
java.net.SocketTimeoutException: Read timed out
        at java.net.SocketInputStream.socketRead0(Native Method)
        at java.net.SocketInputStream.socketRead(Unknown Source)
        at java.net.SocketInputStream.read(Unknown Source)
        at java.net.SocketInputStream.read(Unknown Source)
        at java.io.FilterInputStream.read(Unknown Source)
        at java.io.BufferedInputStream.fill(Unknown Source)
        at java.io.BufferedInputStream.read1(Unknown Source)
        at java.io.BufferedInputStream.read(Unknown Source)
        at java.io.FilterInputStream.read(Unknown Source)
        at <my code from here on>

似乎没有防火墙,但当互联网连接速度更快时,下载就会接续(可能会有某种超时)。我认为问题在于连接,但问题是FileZilla成功地下载了相同的文件。

因此,我可以这样重新表述我的问题:如何使我的FTPClient在下载文件时表现得像FileZilla。也许,在ping逻辑上有一些我不知道的复杂的重试。

公地网:公地-网-3.6

FTP服务器: proftpd-1.3.3g-6.el5在CentOS 5.8上具有默认配置,不支持TLS上的FTP。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-01-05 16:25:29

我不知道造成这种现象的实际原因是什么(在文件的最后一块上超时),但我已经与Wireshark检查了FileZilla下载文件是做什么的,发现同样的超时也存在同样的问题,它正在重新连接到服务器,并发送REST FTP查询重新启动这个特定文件的下载,从文件中止时开始,即只下载最后一块文件。

因此,解决方案是在下载过程中添加某种重试逻辑,以便这段代码:

代码语言:javascript
复制
InputStream in = new BufferedInputStream(client.retrieveFileStream(ftpFilePath), 16384);
// ...
byte[] buffer = new byte[8192];
while ((rd = in.read(buffer)) > 0) {

变成这样:

代码语言:javascript
复制
InputStream in = new BufferedInputStream(client.retrieveFileStream(ftpFilePath), 16384);
// ...
byte[] buffer = new byte[8192];
long totalRead = 0;
for (int resumeTry = 0; resumeTry <= RESUME_TRIES; ++resumeTry) {
    try {
        while ((rd = in.read(buffer)) > 0) {
            //...
            totalRead += rd;
        }
        break;
    } catch (SocketTimeoutException ex) {
        // omitting exception handling
        in.close();
        client.abort();
        client.connect(...);
        client.login(...);
        client.setFileType(FTPClient.BINARY_FILE_TYPE);
        client.enterLocalPassiveMode();
        client.setRestartOffset(totalRead);
        in = client.retrieveFileStream(...);
        if (in == null) {
            // the FTP server doesn't support REST FTP query
            throw ex;
        }
        in = new BufferedInputStream(in, 16384);
    }
}
票数 2
EN

Stack Overflow用户

发布于 2018-01-04 11:19:29

它似乎是由在下面一行中定义的数据超时引起的:

代码语言:javascript
复制
client.setDataTimeout(20000);

根据JavaDoc的说法:

设置从数据连接读取时要使用的超时(毫秒)。此超时将在打开数据连接后立即设置,条件是该值为≥0。 注意:在建立活动本地数据连接时,调用accept()时也会应用超时。 参数:超时值-打开数据连接套接字时使用的默认超时(毫秒)。值0表示无限超时。

您是否可以尝试将此值设置为0(在此上下文中这意味着无限)?

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48093928

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档