示例使用 JDK 內置 sun.net.ftp.FtpClient(內部 API,不建議生產環境直接使用)。生產環境推薦 Apache Commons Net:
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.9.0</version>
</dependency>
public void listFiles(String server, String user, String password, String path) {
try (FTPClient ftp = new FTPClient()) {
ftp.connect(server);
ftp.login(user, password);
if (path != null && !path.isEmpty()) ftp.changeWorkingDirectory(path);
FTPFile[] files = ftp.listFiles();
for (FTPFile file : files) {
System.out.printf("%s %12d %s%n",
file.isDirectory() ? "DIR" : "FILE",
file.getSize(),
file.getName());
}
ftp.logout();
} catch (IOException e) {
e.printStackTrace();
}
}
public void downloadFile(String server, String user, String password,
String remotePath, String remoteFile, String localFile) {
try (FTPClient ftp = new FTPClient();
FileOutputStream fos = new FileOutputStream(localFile)) {
ftp.connect(server);
ftp.login(user, password);
if (remotePath != null && !remotePath.isEmpty()) ftp.changeWorkingDirectory(remotePath);
ftp.setFileType(FTP.BINARY_FILE_TYPE); // 關鍵:二進制模式
ftp.retrieveFile(remoteFile, fos);
ftp.logout();
} catch (IOException e) {
e.printStackTrace();
}
}
public void uploadFile(String server, String user, String password,
String remotePath, String localFile, String remoteFile) {
try (FTPClient ftp = new FTPClient();
FileInputStream fis = new FileInputStream(localFile)) {
ftp.connect(server);
ftp.login(user, password);
if (remotePath != null && !remotePath.isEmpty()) ftp.changeWorkingDirectory(remotePath);
ftp.setFileType(FTP.BINARY_FILE_TYPE);
ftp.storeFile(remoteFile, fis);
ftp.logout();
} catch (IOException e) {
e.printStackTrace();
}
}
| 要點 | 說明 |
|---|---|
| 二進制模式 | setFileType(FTP.BINARY_FILE_TYPE) 必須設置,否則文本模式會損壞圖片/壓縮包等二進制文件 |
| 被動模式 | 防火牆/NAT 環境下必須 ftp.enterLocalPassiveMode() |
| 編碼設置 | 中文文件名需 ftp.setControlEncoding("UTF-8") |
| 資源管理 | try-with-resources 確保流與連接關閉 |
| 異常處理 | 區分連接失敗、認證失敗、文件不存在、權限不足等異常類型 |
| 大文件斷點續傳 | 使用 setRestartOffset() 實現斷點續傳 |
| FTPS/SSL | 生產環境強制使用 FTPSClient 加密傳輸 |
public class FtpUtils {
private FTPClient ftp;
public void connect(String host, int port, String user, String pass, boolean passive, String encoding) throws IOException {
ftp = new FTPClient();
ftp.connect(host, port);
ftp.login(user, pass);
if (passive) ftp.enterLocalPassiveMode();
if (encoding != null) ftp.setControlEncoding(encoding);
ftp.setFileType(FTP.BINARY_FILE_TYPE);
}
public boolean upload(String remoteDir, String localFile, String remoteName) { ... }
public boolean download(String remoteDir, String remoteFile, String localFile) { ... }
public List list(String remoteDir) { ... }
public void disconnect() { if (ftp != null && ftp.isConnected()) ftp.logout(); }
}
FTP 客戶端開發核心在於:連接參數正確、二進制模式、被動模式、編碼處理、資源安全釋放。生產環境請直接使用 Apache Commons Net,避免使用內部 API,並根據業務需求添加重試、超時、進度回調、斷點續傳、SSL 加密等企業級特性。