使用Apache FTPClient 读取文件信息
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());
}
参考地址