问题解决:FTPClient在centos7上下载文件之后,文件大小不一致,缺失字符
问题场景
最近有一个采集任务,需要使用spring-boot项目从FTP服务器下载二进制文件到本地,并进行清洗适配。这里使用FTPClient在centos7上下载文件之后,清洗一直报错。后来跟踪到最后,才发现是文件大小不一致,缺失字符,导致清洗时截取字段有问题。
问题环境
| 软件 | 版本 |
|---|---|
| centos | 7 |
| jdk | 8 |
问题原因
文件是二进制文件,而我们使用FTPClient的代码如下:
ftpClient.enterLocalPassiveMode();
InputStream in = null;
ByteArrayOutputStream output = null;
try {
in = ftpClient.retrieveFileStream(ftpFilePath);
output = new ByteArrayOutputStream();
byte[] buffer = new byte[1024 * 4];
int len = 0;
while ((len = in.read(buffer)) != -1) {
output.write(buffer, 0, len);
}
} catch (Exception e) {
throw e;
} finally {
if (in != null) {
in.close();
}
if (output != null) {
output.close();
}
if (ftp != null) {
if (!ftp.getClient().completePendingCommand()) {
log.warn("ftp 关闭连接,对应的ITEM信息如下:{}",itemInfo);
}
}
}
这个字符缺失的问题,是因为在传输过程中,做了特定的转换,导致了字符减少。那为什么会发生转换呢?这里就得来说一下FTP传输时候的文件类型设置了。

一般在跑程序的时候,我们会选择ASCII模式或者BINARY模式,而这两者的区别是对于回车换行的处理。BINARY模式不对数据进行任何处理,ASCII模式将回车换行转换为本机的回车字符,比如:UNIX下是\n,Windows下是\r\n,Mac下是\r。 比如说,在ASCII模式下会转换文件,这是因为不同的系统有不同的行结束符,如果不做转换,下载下来的文件就会存在显示的问题。UNIX系统下行结束符是一个字节,即十六进制的0A,而Windows的系统是两个字节,即十六进制的0D0A,所以当你用ASCII方式从UNIX的FTP服务器下载文件到Windows系统上时(不管是什么文件),每检测到一个字节是0A,就会自动插入一个0D。所以很显然,我们这里的原始文件是二进制文件,而FTPClient默认是ASCII模式,将其做了自动替换,导致了最后的文件大小减少。 不过,如果文件本身就是UNIX下的文本文件,使用ASCII模式是正确的,要是使用了BINARY模式,我们在Windows上看这个文件是没有换行的,里面是一个个的黑方块。
解决方案
所以,我们在这里要设置FILE_TYPE为BINARY,最后正确的代码如下:
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
ftpClient.enterLocalPassiveMode();
InputStream in = null;
ByteArrayOutputStream output = null;
try {
in = ftpClient.retrieveFileStream(ftpFilePath);
output = new ByteArrayOutputStream();
byte[] buffer = new byte[1024 * 4];
int len = 0;
while ((len = in.read(buffer)) != -1) {
output.write(buffer, 0, len);
}
} catch (Exception e) {
throw e;
} finally {
if (in != null) {
in.close();
}
if (output != null) {
output.close();
}
if (ftp != null) {
if (!ftp.getClient().completePendingCommand()) {
log.warn("ftp 关闭连接,对应的ITEM信息如下:{}",itemInfo);
}
}
}
结果
顺利执行下去,并且最后的清洗也没有报错了。

总结
FTP文件传输还有很多学问可以学习,再接再厉!
随缘求赞
如果我的文章对大家产生了帮忙,可以在文章底部点个赞或者收藏;
如果有好的讨论,可以留言;
如果想继续查看我以后的文章,可以左上角点击关注

浙公网安备 33010602011771号