2010-08-10 65 views
5

我正在尝试使用apache commons-net进行ftp文件传输。commons-net ftp正在上传损坏的文件

问题是文件间歇性地到达服务器损坏。通过'腐败'我的意思是,WinRAR告诉我一个zip文件有'意外的档案结束'。有时文件是完全空的。我注意到这种情况发生在更大的文件(100kb +)上,但是对于小文件也是如此(20kb)。

我知道一个事实,即上传的源zip文件是有效的,只有243kb。

我没有从代码中得到任何错误/异常。

这里是正在执行的代码:

try 
    { 
     int CON_TIMEOUT = (int) TimeUnit.SECONDS.toMillis(20); // fail if can't connect within 20 seconds 
     int LIVE_TIMEOUT = (int) TimeUnit.MINUTES.toMillis(5); // allow up to 5 minutes for data transfers 

     FTPClient client = new FTPClient(); 
     client.setConnectTimeout(CON_TIMEOUT); 
     client.setDataTimeout(LIVE_TIMEOUT); 
     client.connect(host); 
     client.setSoTimeout(LIVE_TIMEOUT); 
     client.login(user, pass); 
     client.changeWorkingDirectory(dir); 
     log("client ready"); 

     File file = new File(filePath); 
     String name = new Date().getTime() + "-" + file.getName(); 

     InputStream fis = null; 
     try 
     { 
      fis = new FileInputStream(file); 
      if (!client.storeFile(name, fis)) 
       throw new RuntimeException("store failed"); 
      log("store " + name + " complete"); 
     } 
     finally 
     { 
      IOUtils.closeQuietly(fis); 
      try 
      { 
       client.logout(); 
       log("logout"); 
      } 
      catch (Throwable e) 
      { 
       log("logout failed", e); 
      } 
      try 
      { 
       client.disconnect(); 
       log("disconnect"); 
      } 
      catch (Throwable e) 
      { 
       log("disconnect failed", e); 
      } 
     } 
    } 
    catch (Throwable e) 
    { 
     log("transfer failed", e); 
    } 

有的日志:

2010-08-10 21:32:38 client ready 
2010-08-10 21:32:49 store 1281439958234-file.zip complete 
2010-08-10 21:32:49 logout 
2010-08-10 21:32:49 disconnect 
2010-08-10 21:32:50 client ready 
2010-08-10 21:33:00 store 1281439970968-file.zip complete 
2010-08-10 21:33:00 logout 
2010-08-10 21:33:00 disconnect 
2010-08-10 21:33:02 client ready 
2010-08-10 21:33:11 store 1281439982234-file.zip complete 
2010-08-10 21:33:11 logout 
2010-08-10 21:33:11 disconnect 
2010-08-10 21:33:15 client ready 
2010-08-10 21:33:25 store 1281439995890-file.zip complete 
2010-08-10 21:33:26 logout 
2010-08-10 21:33:26 disconnect 
2010-08-10 21:33:27 client ready 
2010-08-10 21:33:36 store 1281440007531-file.zip complete 
2010-08-10 21:33:36 logout 
2010-08-10 21:33:36 disconnect 
2010-08-10 21:33:37 client ready 
2010-08-10 21:33:48 store 1281440017843-file.zip complete 
2010-08-10 21:33:48 logout 
2010-08-10 21:33:48 disconnect 
2010-08-10 21:33:49 client ready 
2010-08-10 21:33:59 store 1281440029781-file.zip complete 
2010-08-10 21:33:59 logout 
2010-08-10 21:33:59 disconnect 
2010-08-10 21:34:00 client ready 
2010-08-10 21:34:09 store 1281440040812-file.zip complete 
2010-08-10 21:34:09 logout 
2010-08-10 21:34:09 disconnect 
2010-08-10 21:34:10 client ready 
2010-08-10 21:34:23 store 1281440050859-file.zip complete 
2010-08-10 21:34:24 logout 
2010-08-10 21:34:24 disconnect 
2010-08-10 21:34:25 client ready 
2010-08-10 21:34:35 store 1281440065421-file.zip complete 
2010-08-10 21:34:35 logout 
2010-08-10 21:34:35 disconnect 

注意,所有的这15秒内是完全的,并且所有的服务器上生成的文件已损坏。

我也测试没有设置任何超时,问题仍然存在。

回答

13

Commons FTP默认为ascii文件类型。在处理二进制数据(如zip文件)时,您希望将其设置为Binary。

http://commons.apache.org/net/api/org/apache/commons/net/ftp/FTPClient.html

的FTPClient的默认设置是它使用FTP.ASCII_FILE_TYPE,FTP.NON_PRINT_TEXT_FORMAT,FTP.STREAM_TRANSFER_MODE和FTP.FILE_STRUCTURE。唯一直接支持的文件类型是FTP.ASCII_FILE_TYPE和FTP.BINARY_FILE_TYPE。

您希望在发送文件之前执行setFileType(FTP.BINARY_FILE_TYPE)。

+0

我应该在通过'new ByteArrayInputStream(“字符串”.getBytes())'发送内容时使用二进制吗? – pstanton 2010-08-10 11:58:06

+0

我不是100%确定。这可能更安全。应该足够快以进行测试。 – PaulJWilliams 2010-08-10 12:01:25

+0

你是怎么修复它的?我也有同样的问题。 – itro 2012-03-01 15:43:17

0

我虽然指定binary file type所以我写的代码通过MD5散列验证上传的文件有这个问题:

public void upload(String sourceFilePath) throws Exception 
{ 
    while (true) 
    { 
     // Upload 
     File sourceFile = new File(sourceFilePath); 
     String sourceFileHash = MD5Checksum.getMD5Checksum(sourceFilePath); 
     String remoteFile = sourceFile.getName(); 

     try (InputStream inputStream = new FileInputStream(sourceFile)) 
     { 
      boolean successful = ftpClient.storeFile(remoteFile, inputStream); 

      if (!successful) 
      { 
       throw new IllegalStateException("Upload of " + sourceFilePath + " failed!"); 
      } 
     } 

     // Download 
     File temporaryFile = File.createTempFile("prefix", "suffix"); 
     try (OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(temporaryFile))) 
     { 
      boolean successful = ftpClient.retrieveFile(remoteFile, outputStream); 

      if (!successful) 
      { 
       throw new IllegalStateException("Download of " + sourceFilePath + " failed!"); 
      } 
     } 

     String downloadFileHash = MD5Checksum.getMD5Checksum(temporaryFile.getAbsolutePath()); 
     Files.delete(temporaryFile.toPath()); 

     // Make sure the file hashes match 
     if (sourceFileHash.equals(downloadFileHash)) 
     { 
      break; 
     } 
    } 
} 

MD5Checksum.java

import java.io.*; 
import java.security.MessageDigest; 

public class MD5Checksum 
{ 
    private static byte[] createChecksum(String filename) throws Exception 
    { 
     try (InputStream fileInputStream = new FileInputStream(filename)) 
     { 
      byte[] buffer = new byte[1024]; 
      MessageDigest complete = MessageDigest.getInstance("MD5"); 
      int numRead; 

      do 
      { 
       numRead = fileInputStream.read(buffer); 
       if (numRead > 0) 
       { 
        complete.update(buffer, 0, numRead); 
       } 
      } while (numRead != -1); 

      return complete.digest(); 
     } 
    } 

    public static String getMD5Checksum(String filename) throws Exception 
    { 
     byte[] checksum = createChecksum(filename); 
     StringBuilder result = new StringBuilder(); 

     for (byte singleByte : checksum) 
     { 
      result.append(Integer.toString((singleByte & 0xff) + 0x100, 16).substring(1)); 
     } 

     return result.toString(); 
    } 
} 

MD5代码是从here拍摄。