commons2.0FTP组件开发上传时间过长程序假死解决方案

2017年8月14日 由 Creater 留言 »

最近使用apache上面的commons 2.0开发ftp使用过程中,因为涉及到大文件的长时间传输,在最后经常导致程序死掉。其中传文件的代码如下:

/** 
 * 上传文件到服务器,新上传和断点续传 
 * @param remoteFile 远程文件名,在上传之前已经将服务器工作目录做了改变 
 * @param localFile 本地文件File句柄,绝对路径 
 * @param processStep 需要显示的处理进度步进值 
 * @param ftpClient FTPClient引用 
 * @return 
 * @throws IOException 
 */  
public boolean uploadFile(String remoteFile,File localFile,FTPClient ftpClient,long remoteSize) throws IOException{  
    boolean status;  
    //显示进度的上传  
    long step = localFile.length() / 100;  
    long process = 0;  
    long localreadbytes = 0L;  
    RandomAccessFile raf = new RandomAccessFile(localFile,"r");  
    OutputStream out = ftpClient.appendFileStream(new String(remoteFile.getBytes("GBK"),"iso-8859-1"));  
    //断点续传设置起始位置  
    if(remoteSize>0){  
        ftpClient.setRestartOffset(remoteSize);  
        process = remoteSize /step;  
        raf.seek(remoteSize);  
        localreadbytes = remoteSize;  
    }  
    byte[] bytes = new byte[1024];  
    int c;  
    //开始上传  
    while((c = raf.read(bytes))!= -1){  
        out.write(bytes,0,c);  
        localreadbytes+=c;  
        if(localreadbytes / step != process){  
            process = localreadbytes / step;  
//          System.out.println("上传进度:" + process);  
            //TODO 添加汇报上传状态内容  
        }  
    }  
    logger.info("清空输出流");  
    out.flush();  
    logger.info("关闭文件读句柄");  
    raf.close();  
    logger.info("关闭输出流");  
    out.close();  
    logger.info("关闭输出流成功");  
    boolean status = ftpClient.completePendingCommand();  
    logger.info("从上传方法返回");  
    return status;  
}  

如果上传大的文件,比如说是500M文件,ftp传输大概需要两个小时左右的时候,ftpClient.completePendingCommand()方法就会死掉,我在网上也查了一些内容,说是打开的流必须关闭后ftp Server才会返回正确的状态吗。问题是我关闭了同样没有收到正确的状态码。

如果换成appendFile(String remoteFile,InputStream in)这种方法就不会存在问题,

问题在于completePendingCommand()方法始终不能返回,介绍一下我在调试过程中遇到的问题。
1.FTP服务器有控制连接和数据连接,我的猜测是在进行数据传输的过程中,数据连接一直工作,但是控制连接可能就处于空闲状态,造成被服务器主动关闭,因此不能正常返回。
2.在网上也看了一些网友的介绍,说在调用completePendingCommand()方法时必须关闭输入输出流,而调用这个方法主要就是为了拿到服务器端的226相应(File OK)。
3.我的方法再调用completePendingCommand()方法时,输入输出流确实已经关闭,所以上诉的第2点不适合我的程序。
4.另外我对程序进行更改,不调用completePendingCommand()方法,直接返回 后,发现在后续的程序中,如果发送命令(如PASV)到服务器端,收到的响应为226 File receive OK.而后续的基本上都正常了。

综合以上分析我采用如下的方法来处理:
在关闭输入输出流后发送NOOP命令激活控制连接,然后调用completePendingCommand()方法返回。
现在我测试的结果是,即使数据传输3个小时,也不会造成程序假死。

while((c = raf.read(bytes))!= -1){  
    out.write(bytes,0,c);  
    localreadbytes+=c;  
    if(localreadbytes / step != process){  
        process = localreadbytes / step;  
//      System.out.println("上传进度:" + process);  
        //汇报上传状态,汇报进度函数,自己实现  
        reportUploadPercent((int)process);  
    }  
    out.flush();  
}  
raf.close();  
out.close();  
ftpClient.sendNoOp();  
boolean result = ftpClient.completePendingCommand();  
广告位

发表评论

你必须 登陆 方可发表评论.