2017年7月4日 星期二

使用 Java 存取 FTP 伺服器

要存取 FTP 伺服器,簡單地搜尋了五秒,大概就會看到 Apache Commons Net 這個函式庫吧 XD。
包山包海地實作了包括 FTP、NTP、SMTP、Whois 等等的一堆基礎網路相關的協定。
而這篇的目的是為了簡單地紀錄 FTP 的使用方法。(其實真的蠻簡單的 XD)

環境設定

首先在 Maven 裡加上這段 dependency。需要注意的是,因為這裡是用 3.6 版,依照官網的文件寫法,必須要是 Java 1.6 以上版本才行。

<dependency>
    <groupId>commons-net</groupId>
    <artifactId>commons-net</artifactId>
    <version>3.6</version>
</dependency>

與 FTP 伺服器建立連線

public static void getFiles (
    InetAddress host, int port, String username, String password)
        throws IOException {
  log.info("Try to connect to {}:{}...", host, port);
  FTPClient ftp = new FTPClient();
  try {
    /*
     * Establish connection with the FTP server.
     */
    log.debug("Attempt to establish the connection...");
    ftp.connect(host, port);
    int reply = ftp.getReplyCode();
    
    // Validate the status of the connection.
    if (!FTPReply.isPositiveCompletion(reply)) {
      log.error("Cannot connect to FTP server {}:{}.", host, port);
      return;
    }

    // Login to the FTP server.
    ftp.login(username, password);
  } finally {
    log.info("Close connection from FTP server {}:{}.", host, port);
    ftp.disconnect();
  }
}

上述程式碼的第 11 行是與 FTP 伺服器建立連線,並且預期伺服器應該要回覆 2XX 的狀態碼
14~18 行檢查如果狀態碼不是 2XX,則視為連線失敗,程式就結束了(會先執行 finally 切斷連線)。
然後要記得 21 行的登入~。

列出 FTP 伺服器的檔案清單

上述 login 完成後,其實剩下的就很簡單了 XD
舉例來說,想要列出 FTP 伺服器上的檔案,可以用 listFiles() 方法,會回傳一個 FTPFile 的陣列
其中每個 FTPFile 的操作方法,很接近 java.io.File,所以其實還蠻容易懂的。

下載檔案

下載檔案使用的是 retrieveFile() 這個方法,其中必須提供檔案的路徑以及一個 OutputStream。
不過 FTPFile 物件本身好像沒有提供像是 java.io.File 那種能夠列出子目錄等的方法(因為對應的方法是在 FTPClient 上)
所以實際操作檔案時,操作對象幾乎都是 FTPClient,只有遇到需要拿檔案或目錄屬性時,才會使用 FTPFile。
除此之外,FTPClient 在操作時,幾乎都是給路徑的,因此必須要自己組成檔案的線上路徑。

Path srcPath = Paths.get(ftpFile.getName());
// The output path will be formatted as 
// '.../Temp/d2308169-5c97-46f9-b0dd-64fef6a96d19',
// which can ensure that collision is nearly impossible. 
Path destPath = 
    Paths.get(System.getProperty("java.io.tmpdir"), UUID.randomUUID().toString());
log.trace("Attempt to download file '{}' from server to '{}'.", 
    srcPath, destPath);

try (FileOutputStream fos = new FileOutputStream(destPath.toFile())) {
  ftp.retrieveFile(srcPath.toString(), fos);
  log.trace("Download of file '{}' is complete. Size: {}",
      srcPath, destPath.toFile().length());
}

上述的程式碼執行時,會印出類似下面這樣的 log:

Attempt to download file 'aaa.jar' from server to 'C:\Users\User\AppData\Local\Temp\fe088488-a48d-4bab-b4a6-dccde436ac63'.
Download of file 'aaa.jar' is complete. Size: 571575
Attempt to download file 'bbb.7z' from server to 'C:\Users\User\AppData\Local\Temp\116a8fe6-b99e-4487-8803-eb10c3bfbbbf'.
Download of file 'bbb.7z' is complete. Size: 539494
參考資料
  1. Apache Commons Net

沒有留言: