问题场景
最近有一个从ftp下载一个文件文件得需求,写完之后发觉下载正常txt文件正常。不管多大的问题,都能正常下载,而下载zip文件出现大小与实际文件不符得情况,后来跟踪到最后,才发现是文件大小不一致,缺失字符,导致下载ftp文件不全有问题。
问题原因
后来分析了下,发现是因为ftp在传输过程中,做了特定的转换,导致了字符减少.
FTPClient默认是ASCII模式
ftp传输方式有两种方式:ASCII传输模式(默认)和二进制数据传输模式。
- ASCII传输方式 假定用户正在拷贝的文件包含的简单ASCII码文本,如果在远程机器上运行的不是UNIX,当文件传输时ftp通常会自动地调整文件的内容以便于把文件解释成另外那台计算机存储文本文件的格式。
但是常常有这样的情况,用户正在传输的文件包含的不是文本文件,它们可能是程序,数据库,字处理文件或者压缩文件(尽管字处理文件包含的大部分是文本,其中也包含有指示页尺寸,字库等信息的非打印字符)。在拷贝任何非文本文件之前,用binary 命令告诉ftp逐字拷贝,不要对这些文件进行处理,这也是下面要讲的二进制传输。
- 二进制传输模式 在二进制传输中,保存文件的位序,以便原始和拷贝的是逐位一一对应的。即使目的地机器上包含位序列的文件是没意义的。例如,macintosh以二进制方式传送可执行文件到IBM VM系统,在对方系统上,此文件不能执行。(但是,它可以从VM系统上以二进制方式拷贝到另一macintosh,是可以执行的)。
如果你在ASCII方式下传输二进制文件,即使不需要也仍会转译。这会使传输稍微变慢也会损坏数据,使文件变得不能用。(在大多数计算机上,ASCII方式一般假设每一字符的第一有效位无意义,因为ASCII字符组合不使用它。如果你传输二进制文件,所有的位都是重要的。)如果你知道这两台机器是同样的,则二进制方式对文本文件和数据文件都是有效的。
一般在跑程序的时候,我们会选择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, 最后正确的代码如下:
注: 常见文件类型传输方式