commons-net ftp est des fichiers corrompus de téléchargement des
-
27-09-2019 - |
Question
Je suis en train d'utiliser apache commons-net pour les transferts de fichiers FTP.
Le problème est les fichiers arrivent par intermittence au niveau du serveur corrompu. par « corrompu » je veux dire que winrar me dit un fichier zip a une « fin inattendue d'archives ». parfois les fichiers sont complètement vides. J'ai remarqué que cela se produit plus pour des fichiers plus volumineux (100kb +), ne cependant se produire pour de petits fichiers trop (20kb).
Je sais pertinemment que le fichier zip source en cours de téléchargement est valide et est seulement 243ko.
Je ne reçois pas des erreurs / exceptions du code.
Voici le code en cours d'exécution:
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);
}
et certains journaux:
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
Notez que tous ces étaient complets dans les 15 secondes, et tous les fichiers obtenus sur le serveur sont corrompus.
i ont également testé sans poser de délais d'attente et le problème se produit encore.
La solution
par défaut Commons FTP à des types de fichiers ascii. Vous voulez le mettre à binaire lors du traitement de données binaires comme un fichier zip.
De http: //commons.apache .org / net / api / org / apache / communes / net / ftp / FTPClient.html
Les paramètres par défaut de ClientFTP sont pour elle d'utiliser FTP.ASCII_FILE_TYPE, FTP.NON_PRINT_TEXT_FORMAT, FTP.STREAM_TRANSFER_MODE et FTP.FILE_STRUCTURE. Les seuls types de fichiers pris en charge directement sont FTP.ASCII_FILE_TYPE et FTP.BINARY_FILE_TYPE.
vous voulez faire setfiletype (FTP.BINARY_FILE_TYPE) avant d'envoyer le fichier.
Autres conseils
J'ai eu ce problème, malgré la spécification binary file type
j'ai donc écrit le code pour valider le fichier téléchargé via hashing 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();
}
}