Maven依賴
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.3</version>
</dependency>
使用案例
@Test
void testFtp() throws IOException {
FTPClient ftpClient = new FTPClient();
// 設置FTP服務器編碼,影響中文路徑讀取,常用windows:gbk,linux:utf-8
ftpClient.setControlEncoding("GBK");
ftpClient.connect("127.0.0.1", 21);
ftpClient.login("usert", "1");
// 設置傳輸文件類型,默認為 FTP.ASCII_FILE_TYPE,可能使換行符被替換導致文件被破壞
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
try (InputStream in = ftpClient.retrieveFileStream("/test/中文.xlsx")) {
// ...
} finally {
// 等待FTP Server返回226 Transfer complete
ftpClient.completePendingCommand();
}
}
解決讀取中文路徑亂碼
需要在連接之前設置FTP服務器的編碼
// 設置FTP服務器編碼,影響中文路徑讀取,常用windows:gbk,linux:utf-8
ftpClient.setControlEncoding("GBK");
ftpClient.connect("127.0.0.1", 21);
解決讀取excel(xlsx)時丟失字節
在linux下使用FTPClient下載部分xlsx文件時發生了文件損壞,對比發現文件丟失了部分字節。
解決這個問題需要在登錄之后、讀取文件之前修改文件傳輸類型
ftpClient.login("usert", "1");
// 設置傳輸文件類型,默認為 FTP.ASCII_FILE_TYPE,可能使換行符被替換導致文件被破壞
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
解決連續讀取文件流時,返回流為空
public InputStream retrieveFileStream(String remote)
public OutputStream storeFileStream(String remote)
在使用上述方法讀取文件流后需要調用ftpClient.completePendingCommand(); 否則可能導致后續的部分其他操作失效。該方法會阻塞直到流的close()方法被調用。
當獲取的InputStream為空或者未獲取流而調用completePendingCommand()方法時,會導致程序卡住。
String dir = "/test";
FTPFile[] ftpFiles = ftpClient.listFiles(dir, FTPFile::isFile);
for (FTPFile ftpFile : ftpFiles) {
String filePath = dir + "/" + ftpFile.getName();
InputStream in = null;
try {
in = ftpClient.retrieveFileStream(filePath);
System.out.println(in == null);
} finally {
if (in != null) {
in.close();
// 獲取文件流需要調用,此方法會阻塞直到流close()被調用
ftpClient.completePendingCommand();
}
}
}
實測發現在流的close()方法前調用completePendingCommand()也可以正常工作
try (InputStream in = ftpClient.retrieveFileStream(filePath);){
System.out.println(in == null);
if (in != null) {
// 獲取文件流需要調用,此方法會阻塞直到流被關閉
ftpClient.completePendingCommand();
}
}
如果使用以下方法上傳、下載文件則不用也不該調用該方法
public boolean storeFile(String remote, InputStream local)
public boolean retrieveFile(String remote, OutputStream local)
獲取FTP上文件大小(字節)
使用FTPFile.getSize()
如果使用獲取InputStream + InputStream.available()方法,得到文件大小是可能存在誤差的,網絡傳輸存在誤差。
String dir = "/test";
FTPFile[] ftpFiles = ftpClient.listFiles(dir, FTPFile::isFile);
for (FTPFile ftpFile : ftpFiles) {
System.out.println(ftpFile.getSize());
}
參考地址