2014-09-26 118 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)); 
            } 
           } 
          } 
    
相關問題