2014-09-26 121 views
1

我使用apache的FTPClient从FTP服务器下载文件。我的情况是 - FTP服务器可能会松动网络连接,并可能在最多1天内保持断开状态。当它连接回来时,文件的下载应该从剩下的地方开始。我使用下面的代码连接到服务器,然后从服务器下载文件使用apache FTPClient从FTP服务器下载文件

public void retrieve(String server, int port, String username, 
     String password, String remote, String local, int fileType, 
     ProgressHandler progressHandler) throws Exception {  
    final FTPClient ftp = new FTPClient(); 
    Date date = new Date(); 
    long startTime_ms = date.getTime(); 
    if (progressHandler != null) { 
     ftp.setCopyStreamListener(new FtpCopyStreamListener(progressHandler)); 
    } 

    ftpConnect(server,ftp, port,startTime_ms); 


    if(ftp.getReplyCode()==0 || !String.valueOf(ftp.getReplyCode()).startsWith("2")){ 
     cleanup(ftp, "Could not log into server: " + server, null); 
     return; 
    } 

    boolean loggedIn = false; 
    try { 
     if (username == null || username.isEmpty()) { 
      username = "anonymous"; 
      password = System.getProperty("user.name") + "@" 
        + InetAddress.getLocalHost().getHostName(); 
     } 
     if (!ftp.login(username, password)) { 
      ftp.logout(); 
      cleanup(ftp, "Could not log into server: " + server, null); 
     } 
     loggedIn = true; 

     ftp.setFileType(fileType); 
     ftp.enterLocalPassiveMode(); 
     OutputStream output = null; 
     try { 
      output = new FileOutputStream(local); 
      LOGGER.info("About to download " + remote + " from " + server 
        + " on " + (port > 0 ? port : ftp.getDefaultPort()) 
        + " to " + local);    
      ftp.setControlKeepAliveTimeout(300); 
      boolean isFileDownloaded = false; 
      try{ 
       isFileDownloaded = ftp.retrieveFile(remote, output); 

      } 
      catch(IOException ex){ 
       if(ftp.isConnected()){ 

        try{ 
         int retryCode = 0; 
         while (!String.valueOf(retryCode).startsWith("2") && (new Date().getTime() < (startTime_ms + TOTAL_DURATION_MSECS))){ 
          try{ 

           retryCode = ftp.retr(local); 
          }catch(Exception e1){ 
           Thread.sleep(1000); 
           System.out.println("File not downloaded !! " + e1.toString()); 
           ftpConnect(server, ftp, port, startTime_ms); 
          } 

         } 
        }catch(Exception e){ 
         //ftp.getReplyCode() 
         //throw e; 
         //disconnect(ftp); 
         //ftpConnect(server, ftp, port, startTime_ms); 

         System.out.println("File not downloaded !! " + e.toString()); 
        }     
       } 
      } 
      if(isFileDownloaded){ 
       LOGGER.info("Finished downloading " + remote + " from " 
         + server + " on " 
         + (port > 0 ? port : ftp.getDefaultPort()) + " to " 
         + local); 
      } 
      else{ 
       System.out.println("File not downloaded !! "); 
      }   

     }catch(IOException io){ 
      io.printStackTrace(); 

      throw io; 
     }   
     finally { 
      if (output != null) { 
       try { 
        output.close(); 
       } catch (IOException f) { 
        LOGGER.severe("output.close() error: " 
          + ServiceUtils.stackToString(f)); 
       } 
      } 
     } 
    }  
    catch (FTPConnectionClosedException e) { 
     LOGGER.severe("Server closed connection: " + server + " " 
       + ServiceUtils.stackToString(e)); 
     throw e; 
    } catch (IOException e) { 
     LOGGER.severe("IOException, server: " + server + " " 
       + ServiceUtils.stackToString(e)); 
     throw e; 
    } finally { 
     if (loggedIn) { 
      try { 
       ftp.logout(); 
      } catch (IOException f) { 
       LOGGER.severe("ftp.logout() error: " 
         + ServiceUtils.stackToString(f)); 
      } 
     } 
     disconnect(ftp); 
    } 
} 

我的问题基本上是如果retrieveFile()方法失败没有任何反正我可以重新连接并开始从点下载它被断开。

现在我正在使用Microsoft IIS服务器作为我的FTP服务器,但在生产环境中它将成为FileZilla FTP服务器。

任何帮助表示赞赏。 谢谢

+0

见[重启()](http://commons.apache.org/proper/commons-net/apidocs/org/apache/commons/net/ftp/FTPClient。html#restart%28long%29),因为它工作的服务器应该支持'REST'命令 – fvu 2014-09-26 20:42:05

+0

@fvu我试过rest()方法,但它并没有启动文件下载恢复过程。你能分享一些代码片段吗? – Anirban 2014-09-26 22:37:08

回答

0

FTPCLient.restart(...)protected。我认为setRestartOffset(...)retrieveFile(...)是要走的路:“注意:如果您使用了setRestartOffset(long),则文件数据将从所选偏移量开始。”

我也想搭上CopyStreamException,而不是仅仅IOException“的CopyStreamException允许你确定传输的字节数””。

在进入重试块之前检查ftp.isConnected()但您编写“FTP服务器松动的网络连接并可能保持断开连接”。我想如果你输入这个catch块连接已经丢失了,这就是进入这个块的原因之一。

什么是ftp.retr(...)在做什么?重试,是的,但它按预期工作吗?

您能得到什么,如果你通过调试代码:

  • ftp.isConnected()
  • 设置断点检索文件,是大到足以需要一段时间才能下载
  • 拉出网络电缆而转移正在进行中
  • 看价值ftp.isConnected()
  • 如果是true(不太可能,但谁知道)做什么es ftp.retr(...)返回?
+0

如果我停止我的FTP服务器(不重新连接网络电缆,因为重新连接将动态IP重新分配给服务器),ftp.isConnected()让我错误。当我使用ftpConnect()方法[这是一个迭代过程来检查网络连接是否已建立]再次连接回来,然后调用setRestartOffset(1000)[只是一个示例]&retrieveFile(),这不会开始下载处理。相反,如果进入无限循环,我需要手动杀死进程。 – Anirban 2014-09-27 01:10:36

+0

我最后忽略了它是_your_服务器。 (因此“拉”:-)你调试过单步并检查循环中涉及的表达式的值吗?这是否显示它在何处/为什么会循环/停止? – 2014-09-27 01:55:53

1

对不起,很迟才回复。在这里我做了什么来解决这个问题:

  1. 设置一个FileZilla的服务器
  2. 使用retrieveFileStream代替retrieveFile。
  3. 保持写入的字节数并使用相同的输出流写入。

    BufferedInputStream inputStream = null; 
        BufferedOutputStream outputStream = null; 
        InputStream in = null; 
        int osCount = 0; 
        in = ftp.retrieveFileStream(remote); 
          inputStream = new BufferedInputStream(in); 
          File localFile = new File(local, fileName); 
          outputStream = new BufferedOutputStream(new FileOutputStream(localFile)); 
          for (int read = inputStream.read(); read != -1; read = inputStream.read()) { 
           outputStream.write(read); 
           osCount++; 
          }   
          outputStream.flush(); 
          if (osCount < fileSize) {      
           System.out.println(fileName + ": Errored out !!!"); 
           BufferedInputStream inputStream1 = null; 
           InputStream in1 = null; 
           if (ftp.isConnected()) { 
            try { 
             while (osCount < fileSize && new Date().getTime() < (startTime_ms + TOTAL_DURATION_MSECS)) { 
              try {          
                disconnect(ftp); 
                ftpConnect(server, ftp, port, startTime_ms); 
                ftp.login(username, password); 
                ftp.setRestartOffset(osCount);          
                System.out.println(fileName + ": Re reading from position " + osCount); 
                in1 = ftp.retrieveFileStream(remote); 
                inputStream1 = new BufferedInputStream(in1); 
                for (int read = inputStream1.read(); read != -1; read = inputStream1.read()) { 
                 outputStream.write(read); 
                 osCount++; 
                } 
                outputStream.flush(); 
                if(FTPReply.isPositiveCompletion(ftp.getReplyCode())){ 
                 isErrored = true; 
                 break; 
                } 
              } catch (Exception e1) { 
               Thread.sleep(1000); 
               LOGGER.severe(fileName + ": File not downloaded " + server + " " + ServiceUtils.stackToString(e1)); 
              } 
             } 
    
            } catch (Exception e) { 
             LOGGER.severe(fileName + ": File not downloaded " + server + " " + ServiceUtils.stackToString(e)); 
            } 
           } 
          } 
    
相关问题