使用 FTPClient 从 "some" 服务器下载的图像已损坏
Images downloaded from "some" servers with FTPClient are corrupted
我需要从 Java 的 FTP 服务器下载 .png 文件。
我有 3 个不同的服务器,每个服务器都包含一个包含完全相同的 .png 文件的文件夹。
在服务器 1 上:
如果我用 FTPClient
(apache.commons.net.ftp) 下载存储在该服务器上的 4686 字节的 .png 文件,我得到一个 4706 字节的 .png 文件,我无法打开它。
如果我用Total Commander下载它,我得到一个4686字节的.png文件,我可以打开它。
在服务器 2 和 3 上:
使用 FTPClient
和 Total Commander,我在这两种情况下都得到了一个 4686 字节的文件,我可以毫无问题地打开它。
我的代码:
FTPClient ftpClient = new FTPClient();
ftpClient.connect("...", PORT);
ftpClient.login("...", "...");
ftpClient.enterLocalPassiveMode();
FTPFile[] imageFiles = ftpClient.listFiles(distantPathForImages);
for (FTPFile imageFile : imageFiles) {
InputStream inputStream = ftpClient.retrieveFileStream(distantPathForImages + imageFile.getName());
OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(new File(PATHDESTCSS + imageFile.getName())));
byte[] bytesArray = new byte[65536];
int bytesRead;
while ((bytesRead = inputStream.read(bytesArray)) != -1) {
outputStream.write(bytesArray, 0, bytesRead);
}
outputStream.close();
inputStream.close();
ftpClient.completePendingCommand();
}
为什么我的文件只有从服务器 1 下载时才会有这些 "extra bytes",我该如何解决这个问题?
您的一个服务器可能试图将文件作为文本传输,而您的 ftp 客户端也认为它接收到文本。
这里是 javadoc 的摘录:
If the current file type is ASCII, the returned InputStream
will convert line separators in the file to the local
representation.
如果你在 windows,每个换行符都将被 'linebreak + cr' 替换,对 png 文件中的所有数据结构造成严重破坏。
此场景的预期字节数为:4686 * (1 + 1 / 256) = 4704.3046875 ,因为平均而言,png 文件中的第 256 个字节应该看起来像一个 ASCII 换行符,并且会因此导致额外添加的字节。您的文件最终有 4706 个字节,这非常接近。
将文件类型设置为 FTP.BINARY_FILE_TYPE
应该可以解决此问题:https://commons.apache.org/proper/commons-net/apidocs/org/apache/commons/net/ftp/FTPClient.html#setFileType(int)
FTPClient
默认使用ascii模式。
您必须使用二进制模式传输二进制文件。
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
即使在 ascii 模式下,您当前的代码也可以在 某些服务器 上工作,如果服务器使用 Windows EOL 序列,因此不会发生转换。即便如此,也可能只是,如果文件偶然不包含任何单独的#13。
我需要从 Java 的 FTP 服务器下载 .png 文件。 我有 3 个不同的服务器,每个服务器都包含一个包含完全相同的 .png 文件的文件夹。
在服务器 1 上:
如果我用 FTPClient
(apache.commons.net.ftp) 下载存储在该服务器上的 4686 字节的 .png 文件,我得到一个 4706 字节的 .png 文件,我无法打开它。
如果我用Total Commander下载它,我得到一个4686字节的.png文件,我可以打开它。
在服务器 2 和 3 上:
使用 FTPClient
和 Total Commander,我在这两种情况下都得到了一个 4686 字节的文件,我可以毫无问题地打开它。
我的代码:
FTPClient ftpClient = new FTPClient();
ftpClient.connect("...", PORT);
ftpClient.login("...", "...");
ftpClient.enterLocalPassiveMode();
FTPFile[] imageFiles = ftpClient.listFiles(distantPathForImages);
for (FTPFile imageFile : imageFiles) {
InputStream inputStream = ftpClient.retrieveFileStream(distantPathForImages + imageFile.getName());
OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(new File(PATHDESTCSS + imageFile.getName())));
byte[] bytesArray = new byte[65536];
int bytesRead;
while ((bytesRead = inputStream.read(bytesArray)) != -1) {
outputStream.write(bytesArray, 0, bytesRead);
}
outputStream.close();
inputStream.close();
ftpClient.completePendingCommand();
}
为什么我的文件只有从服务器 1 下载时才会有这些 "extra bytes",我该如何解决这个问题?
您的一个服务器可能试图将文件作为文本传输,而您的 ftp 客户端也认为它接收到文本。
这里是 javadoc 的摘录:
If the current file type is ASCII, the returned InputStream will convert line separators in the file to the local representation.
如果你在 windows,每个换行符都将被 'linebreak + cr' 替换,对 png 文件中的所有数据结构造成严重破坏。
此场景的预期字节数为:4686 * (1 + 1 / 256) = 4704.3046875 ,因为平均而言,png 文件中的第 256 个字节应该看起来像一个 ASCII 换行符,并且会因此导致额外添加的字节。您的文件最终有 4706 个字节,这非常接近。
将文件类型设置为 FTP.BINARY_FILE_TYPE
应该可以解决此问题:https://commons.apache.org/proper/commons-net/apidocs/org/apache/commons/net/ftp/FTPClient.html#setFileType(int)
FTPClient
默认使用ascii模式。
您必须使用二进制模式传输二进制文件。
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
即使在 ascii 模式下,您当前的代码也可以在 某些服务器 上工作,如果服务器使用 Windows EOL 序列,因此不会发生转换。即便如此,也可能只是,如果文件偶然不包含任何单独的#13。