I'm trying to use Apache Commons Net for FTP file transfers.
Problem is files are intermittently arriving at the server corrupt. By 'corrupt' I mean that WinRAR tells me a ZIP file has an 'Unexpected end of archive'. Sometimes the files are completely empty. I have noticed that this happens more for larger files (100kb+), however does happen for small files too (20kb).
I know for a fact that the source zip file being uploaded is valid, and is only 243kb.
I do not get any errors/exceptions from the code.
Here's the code being executed:
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);
}
}
and some logs:
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
Note that all of these were complete within 15 seconds, and all of the resulting files on the server are corrupt.
I have also tested without setting any timeouts and the problem still occurs.
Commons FTP defaults to Ascii file types. You want to set it to Binary when dealing with binary data like a ZIP file.
From http://commons.apache.org/net/api/org/apache/commons/net/ftp/FTPClient.html
The default settings for FTPClient are for it to use FTP.ASCII_FILE_TYPE , FTP.NON_PRINT_TEXT_FORMAT , FTP.STREAM_TRANSFER_MODE , and FTP.FILE_STRUCTURE . The only file types directly supported are FTP.ASCII_FILE_TYPE and FTP.BINARY_FILE_TYPE .
You want to do setFileType(FTP.BINARY_FILE_TYPE)
before you send the file.
I had the same issue and solved it by calling
ftpClient.setFileType(FTP.BINARY_FILE_TYPE)
before each method retrieveFile
, retrieveFileStream
, storeFile
File is corrupted, because default fileType is FTP.ASCII_FILE_TYPE
. This causes the issue. If you are on linux all bytes \n\r
(windows end of file) are changed into \n
byte. And this corrupt the file.
To avoid this behavior you have to call ftpClient.setFileType(FTP.BINARY_FILE_TYPE)
. Unfortunately, this setup is reset by each connect
method back to ASCII_FILE_TYPE
.
In my case this was reset even by method listFiles
. I guess, that this happened because I use passiveMode
on ftpClient.
So if you want to avoid troubles call setFileType(FTP.BINARY_FILE_TYPE)
right before every file transfer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With