从"某些"下载的图像FTPClient的服务器已损坏

时间:2018-01-29 13:58:38

标签: java ftp apache-commons-net

我需要从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下载它时,我该如何解决这个问题?

2 个答案:

答案 0 :(得分:1)

您的某个服务器可能会尝试将文件作为文本传输,而您的ftp客户端也认为它接收文本。

以下是javadoc的摘录:

  

如果当前文件类型为ASCII,则返回InputStream        将文件中的行分隔符转换为本地        表示。

如果你在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)

答案 1 :(得分:1)

FTPClient默认使用ascii模式。

您必须使用二进制模式传输二进制文件。

ftpClient.setFileType(FTP.BINARY_FILE_TYPE);

如果服务器使用Windows EOL序列,即使在ascii模式下,您当前的代码也可以在某些服务器上工作,因此不会发生转换。即便如此,如果文件偶然不包含任何单独的#13。