2010-08-10 14 views
5

Estoy tratando de usar apache commons-net para transferencias de archivos ftp.commons-net ftp está cargando archivos dañados

Problema es que los archivos llegan intermitentemente al servidor dañado. por 'corrupto' quiero decir que winrar me dice que un archivo zip tiene un 'final inesperado de archivo'. a veces los archivos están completamente vacíos. Me he dado cuenta de que esto sucede más para archivos más grandes (100kb +), sin embargo, también ocurre para archivos pequeños (20kb).

Sé con certeza que el archivo zip de origen que se está cargando es válido, y solo tiene 243kb.

No obtengo ningún error/excepción del código.

Aquí está el código que se está ejecutando:

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); 
    } 

y algunos registros:

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 

nota que todos estos eran completa en 15 segundos, y todos los archivos resultantes en el servidor son corruptos .

También he probado sin establecer ningún tiempo de espera y el problema todavía ocurre.

Respuesta

13

Commons FTP se establece de manera predeterminada en los tipos de archivos ascii. Desea establecerlo en Binario cuando se trata de datos binarios, como un archivo zip.

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

La configuración predeterminada para FtpClient son para que utilice FTP.ASCII_FILE_TYPE, FTP.NON_PRINT_TEXT_FORMAT, FTP.STREAM_TRANSFER_MODE y FTP.FILE_STRUCTURE. Los únicos tipos de archivos soportados directamente son FTP.ASCII_FILE_TYPE y FTP.BINARY_FILE_TYPE.

desea hacer setFileType (FTP.BINARY_FILE_TYPE) antes de enviar el archivo.

+0

¿debo usar binario cuando envío contenido a través de 'new ByteArrayInputStream (" una cadena ".getBytes())'? – pstanton

+0

No estoy 100% seguro. Es probablemente más seguro de esa manera. Debería ser lo suficientemente rápido para probar. – PaulJWilliams

+0

¿Cómo lo arreglaste? Tengo el mismo problema. – itro

0

he tenido este problema a pesar especificando binary file type por lo que escribió el código para validar el archivo cargado a través de MD5 hash:

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(); 
    } 
} 

El código se toma de MD5here.

Cuestiones relacionadas