使用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());
}

参考地址

FTPClient中使用completePendingCommand方法注意事项

FTPClient读取文件流遇到的坑

使用Ftpclient从FTP上进行下载时文件少一个字节,打不开

posted @ 2020-12-24 15:52  9sFresh  阅读(2714)  评论(0编辑  收藏  举报