How to upload to FTP server in Java? - java

I have the following method to upload_files to an FTP server, I am not receiving any errors yet the file is not appearing on the server after its run. What could be the problem?
public static void upload_files(String un, String pw, String ip, String dir, String fn){
FTPClient client = new FTPClient();
FileInputStream fis = null;
try {
client.connect(ip);
client.login(un, pw);
String filename = dir+"/"+fn;
fis = new FileInputStream(filename);
client.storeFile(filename, fis);
client.logout();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fis != null) {
fis.close();
}
client.disconnect();
System.out.println("uploaded");
} catch (IOException e) {
e.printStackTrace();
}
}
}

There are a number of possible issues. Assumption is that you are using FTPClient 3.x from Apache commons-net. If using something else, you should probably indicate that in your question. Ideas:
Check the reply status of the connection to make sure you are connecting as expected. There's an example on how to do this in the JavaDoc.
Your filename variable is the path to the local file you want to send. Is that really the same path you want to use for storing the file on the server (relative to the FTP login root)? It might be, but usually isn't. If not, your first parameter to client.storeFile(...) needs to be changed.
Most FTP servers provide ability to log all actions. Are you able to access yours? If so, that usually quickly makes clear what is going wrong.

Related

FTPClient not letting me write with InputStream

I have a java piece that will FTP a string (long text document) to a remote location. All seems to be working, but I am getting a very long hang time when ftp.storeFile(a,b) is called. This then returns a replyCode 425. It is odd because myData.txt is appearing inside the remote destination, but it is blank. There must be something blocking the input stream? Does anyone know what the issue could be?
Java code:
public void doFTP(){
FTPClient ftp = new FTPClient();
FTPClientConfig config = new FTPClientConfig();
ftp.configure(config);
boolean error = false;
try {
int reply;
String server = "example.com";
ftp.connect(server);
ftp.login(username, password);
reply = ftp.getReplyCode();
if(!FTPReply.isPositiveCompletion(reply)) {
ftp.disconnect();
}
InputStream is = new ByteArrayInputStream(myString.getBytes()); //String
ftp.setFileType(ftp.BINARY_FILE_TYPE, ftp.BINARY_FILE_TYPE);
ftp.setFileTransferMode(ftp.BINARY_FILE_TYPE);
Boolean test = ftp.storeFile("myData.txt", is); //FTP store here
System.out.println(test);
reply = ftp.getReplyCode();
System.out.println(reply);
is.close();
ftp.logout();
} catch(IOException e) {
// ... not important
} finally {
// ... not important
}
}
The code you are showing looks strange to me. where you have the InputStream is =
this code should be inside the try { ..... } code block.
Found the problem, I need to switch it to:
ftp.enterLocalPassiveMode();
I still don't quite understand why this needs to be done, if anyone could care to explain.

How can I improve ftp upload speed for multiple files [Java]

I implemented java code to upload files to server with org.apache.commons.net.ftp.FTPClient
For multiple files the ftp upload speed is very slow.
How can I improve the speed.
-Change library?
What is the powerful FTP client class library for uploading multiple files?
-Use multiple threads?
How can I implement ftp upload function with multiple thread?
Could someone show me an example?
I am a new for multiple threading programming.
After I read all answer, I try to change my code and test it.
Following is a sample FTPClient code:
// create instance of FTPClient
FTPClient ftp = new FTPClient();
ftp.setControlEncoding("UTF-8");
ftp.setDefaultTimeout(30000);
// connect to server
try
{
ftp.connect("10.1.1.1", 990);
}
catch(Exception e)
{
System.out.println("Cannot connect to server");
return;
}
// login to server
if (!ftp.login("username", "password"))
{
ftp.logout();
System.out.println("Cannot login to server");
return;
}
try
{
ftp.setFileTransferMode(FTP.BINARY_FILE_TYPE);
ftp.enterLocalPassiveMode();
// ftp.setBufferSize(0); <-- someone suggest me to set buffer size to 0, but it throw error sometime.
}
catch(Exception e)
{
}
// create directory on server
// dirs is list of required directories on server
for (String dir : dirs)
{
try
{
ftp.makeDirectory(dir);
}
catch(IOException e)
{
}
}
// files is a map of local file and string of remote file
// such as
// file on client is "C://test/a.txt"
// location on server is "/test/a.txt"
for (Map.Entry<File, String> entry : files.entrySet())
{
File localFile = entry.getKey();
String remoteFile = entry.getValue();
FileInputStream input = null;
try
{
input= new FileInputStream(localFile);
ftp.storeFile(remoteFile, input);
}
catch (Exception e)
{
try
{
ftp.deleteFile(remoteFile);
}
catch (IOException e1)
{
}
}
finally
{
if (input != null)
{
try
{
input.close();
}
catch (IOException e)
{
}
}
}
}
// disconnect
if (ftp != null && ftp.isConnected())
{
try
{
ftp.disconnect();
}
catch (IOException f)
{
// do nothing
}
}
When I uploaded 1050 files (each file is about 1-20 KB), it took about 49406 - 51000 millisec (This is upload time only).
I would like to improve the speed.
Some people suggest me to use ftp4j, but when I test the library with 1050 files, the upload speed of ftp4j is slowly than FTPClient about 10000 millisec.
it took about 60000 millisec.
Following is sample ftp4j code:
// create instance of FTPClient
FTPClient ftp = new FTPClient();
ftp.setCharset("UTF-8");
// connect to server
try
{
ftp.connect("10.1.1.1", 990);
}
catch(Exception e)
{
System.out.println("Cannot connect to server")
return;
}
// login to server
try
{
ftp.login("username", "password");
}
catch (Exception e)
{
try
{
ftp.logout();
}
catch (Exception e1)
{
}
System.out.println("Cannot login to server")
return;
}
try
{
ftp.setType(FTPClient.TYPE_BINARY);
ftp.setPassive(true);
}
catch(Exception e)
{
}
// create directory on server
// dirs is list of required directories on server
for (String dir : dirs)
{
try
{
ftp.createDirectory(dir);
}
catch (Exception e)
{
}
}
// files is a map of local file and string of remote file
// such as
// file on client is "C://test/a.txt"
// location on server is "/test/a.txt"
for (Map.Entry<File, String> entry : files.entrySet())
{
final File localFile = entry.getKey();
final String remoteFile = entry.getValue();
BufferedInputStream input = null;
boolean success = false;
try
{
input = new BufferedInputStream(new FileInputStream(localFile));
// ftp.upload(localFile); <-- if I use ftp.upload(File), it will took more time.
ftp.upload(remoteFile, input, 0, 2048, new MyTransferListener());
success = true;
}
catch (Exception e)
{
}
finally
{
if (input != null)
{
try
{
input.close();
}
catch (IOException e)
{
}
}
if (!success)
{
try
{
ftp.deleteFile(remoteFile);
}
catch (Exception e)
{
}
}
}
}
// disconnect
if (ftp != null && ftp.isConnected())
{
try
{
ftp.disconnect();
}
catch (IOException f)
{
// do nothing
}
}
I try to use multiple threads.
Following is multiple threading code:
final CountDownLatch latch = new CountDownLatch(files.size());
ExecutorService pool = Executors.newFixedThreadPool(10);
for (Map.Entry<File, String> entry : files.entrySet())
{
final File localFile = entry.getKey();
final String remoteFile = entry.getValue();
pool.execute(new Runnable() {
public void run()
{
FileInputStream input = null;
try
{
input= new FileInputStream(localFile);
ftp.storeFile(remoteFile, input);
}
catch (Exception e)
{
try
{
ftp.deleteFile(remoteFile);
}
catch (IOException e1)
{
}
}
finally
{
if (input != null)
{
try
{
input.close();
}
catch (IOException e)
{
}
}
latch.countDown();
}
}
});
}
try
{
// waiting for all threads finish
// see: http://stackoverflow.com/questions/1250643/how-to-wait-for-all-threads-to-finish-using-executorservice
latch.await();
}
catch(Exception e)
{
}
Is it correct? It work correctly but it cannot improve speed.
it took about 49000 - 51000 millisec same as the code without thread.
I test the speed with intranet. It will take more time for internet.
How should I do for improve upload speed?
I don't know why, but Apache Commons FTP is pretty slow in uploading, i had the same problem and i couldn't solve it.
Now i use FTP4j, it's pretty similar to apache commons ftp but uploads are really fast.
This is an example:
FTPClient client = new FTPClient();
client.connect("www.yoursite.com");
client.login("login", "password");
client.setPassive(true);
client.setType(FTPClient.TYPE_BINARY);
client.changeDirectory("a");
File f = new File("path/to/your/file");
client.upload(f);
client.disconnect(true);
With this library i uplodaded a 340KB file in less than one second, while with Apache Commons FTP it took about 1 minute.
If you want to transfer different files with threads, try to put every client.upload(f) into a different thread, but i'm not sure it will boost up the transfer.
Quoting #fge previous answer:
Basically, chances are, you can't.
Don't forget that FTP has two types of channels: the command channel and the data channels. One upload is initiated by sending the instructions over the command channel to open a data channel for the upload proper.
Now:
most FTP servers are configured so that one command channel can only open one data channel at anyone time;
there are bandwidth limits: your upstream bandwidth, and the server's downstream bandwidth.
Were it possible to upload several files in parallel, ie, opening more than one data channel, you'd have the problem that the overhead of TCP itself would in fact slow down the upload process in general.
Basically: keep one data channel open at any time. Trying and opening more than one is just not worth it. It may work in ~1% of cases in general. This is just not worth the hassle.
This Q&A some possible explanations of what is going on: why is ftp upload slow in java 7
And furthermore, it offers a couple of workarounds:
Upgrade to the 3.3 snapshot which can (currently) be found here
Call FTPClient.setBufferSize(0).
Apparently there is also a regression in Java 7 for Windows where the firewall application filter for the FTP client is blocking the client from using PASV mode FTP. It is not clear what the best solution to that is, but you could try the following:
Change your Windows firewall to disable the firewall application filter (as described in the Microsoft KB page.
Change your FTP application to use "active" mode ... though this requires that the FTP server can initiate connections to the machine running your clients.
Note: that there seem to be more than one explanation for the problem ... or maybe more than one possible problems.

File not uploading successfully to FTP

I have written a stand alone Program to upload file to FTP Server. Code runs fine but I cannot find the file at FTP. Here is the code
import java.io.FileInputStream;
import java.io.IOException;
import java.net.SocketException;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
public class FTPDemo {
public static void main(String[] args) {
FTPClient ftp = new FTPClient();
int reply;
try {
ftp.connect("ip address");
ftp.login("username","password");
reply = ftp.getReplyCode();
if(FTPReply.isPositiveCompletion(reply)){
System.out.println("Connected Success");
}else {
System.out.println("Connection Failed");
ftp.disconnect();
}
FileInputStream fis = null;
String filename = "demo.txt";
fis = new FileInputStream("C:\\demo.txt");
System.out.println("Is file stored: "+ftp.storeFile(filename,fis));
fis.close();
ftp.disconnect();
} catch (SocketException ex) {
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
Is file stored returns false. What could be the problem ?
Let me quote you the FTPClient documentation:
The convention for all the FTP command methods in FTPClient is such that they either return a boolean value or some other value. The boolean methods return true on a successful completion reply from the FTP server and false on a reply resulting in an error condition or failure. The methods returning a value other than boolean return a value containing the higher level data produced by the FTP command, or null if a reply resulted in an error condition or failure. If you want to access the exact FTP reply code causing a success or failure, you must call getReplyCode after a success or failure.
In other words, to understand the actual reason for failure you need to call ftp.getReplyCode() and work from there.

Java - Storing File on FTP Server fails

I am trying to store a byteArrayInputStream as File on a FTP Server. I could already connect to the Server and change the working path, but triggering the method to store the Stream as File on the Server returns always false.
I am using the apache FTPClient.
Can someone please give me a hint where my mistake can be!?
Here the Code:
String filename = "xyz.xml"
// connection returns true
connectToFtpServer(ftpHost, ftpUser, ftpPassword, exportDirectory);
// byteArray is not void
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArray);
try {
// change returns true
result = ftpClient.changeWorkingDirectory(exportDirectory);
// storing the file returns false
result = ftpClient.storeFile(filename, byteArrayInputStream);
byteArrayInputStream.close();
ftpClient.logout();
} catch (...) {
...
} finally {
// disconnect returns true
disconnectFromFtpServer();
}
I don't believe it's your code. Here is another example that looks very similar from kodejava:
package org.kodejava.example.commons.net;
import org.apache.commons.net.ftp.FTPClient;
import java.io.FileInputStream;
import java.io.IOException;
public class FileUploadDemo {
public static void main(String[] args) {
FTPClient client = new FTPClient();
FileInputStream fis = null;
try {
client.connect("ftp.domain.com");
client.login("admin", "secret");
//
// Create an InputStream of the file to be uploaded
//
String filename = "Touch.dat";
fis = new FileInputStream(filename);
//
// Store file to server
//
client.storeFile(filename, fis);
client.logout();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fis != null) {
fis.close();
}
client.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
I agree it's file permissions. There is not a way to change permissions in java itself yet, but there are other solutions. See this thread: How do i programmatically change file permissions?
HTH,
James
It was actually a permission issue due to an invalid usergroup. After adding my user to the usergroup, i was able to store again files.

Apache Commons FTP problems

I want to implement a FTP Client with Apache Commons Net only for uploading data.
The Connection and Login to FTP-Server works fine.
But the upload does not work right.
The files are a little to big as the originals.
And the files are damaged.
I tried an image, a video and a textfile. Only the textfile is alright.
Now I see while debugging
boolean tmp=client.setFileTransferMode(FTPClient.BINARY_FILE_TYPE);
gives me false. So it can not be set. Why?
(Maybe this is not the problem?)
Here a the rest of my code
client=new FTPClient();
try {
int reply;
client.connect(url, port);
reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply))
{
client.disconnect();
System.err.println("FTP server refused connection.");
System.exit(1);
}
client.login(user, pw);
boolean xxx=client.setFileTransferMode(FTPClient.BINARY_FILE_TYPE);
client.setControlKeepAliveTimeout(300);
client.enterLocalPassiveMode();
if (client.isConnected())
{
try {
File file=new File(<FILE>);
FileInputStream inputStream = new FileInputStream(file);
OutputStream outputStream = client.storeFileStream(file.getName());
byte[] buffer = new byte[4096];
int l;
while((l = inputStream.read(buffer))!=-1)
{
outputStream.write(buffer, 0, l);
}
inputStream.close();
outputStream.flush();
outputStream.close();}
Change the following:
boolean xxx=client.setFileTransferMode(FTPClient.BINARY_FILE_TYPE);
Should be:
boolean xxx=client.setFileType(FTP.BINARY_FILE_TYPE);
You have confused FileTransferModes with FileTypes.
The available FileTypes are:
FTP.ASCII_FILE_TYPE (default)
FTP.BINARY_FILE_TYPE
FTP.EBCDIC_FILE_TYPE
FTP.LOCAL_FILE_TYPE
The available FileTransferModes are:
FTP.STREAM_TRANSFER_MODE (default)
FTP.BLOCK_TRANSFER_MODE
FTP.COMPRESSED_TRANSFER_MODE
I suppose if apache introduced enums for these constant types, then this kind of problem could be avoided, but then the library would not be available to pre-java-5 runtimes.
I wonder how much of an issue java 1.4 compatibility really is.
If only the text file was transferred successfully, I suspect you need to set the binary transfer file type.
See the setFileType method to see how to do this.
The commons-net wiki mentions this is the cause of most file corruption issues.
This work for me, Uploading Image and download after It´s Ok: Using
FTP.LOCAL_FILE_TYPE
this code using logger, replace for you logger or use System.out.println("");
private void cargarData(File filelocal) {
FTPClient client = new FTPClient();
try {
client.connect("URLHOSTFTP", "PORT: DEFAULT 21");
if (!FTPReply.isPositiveCompletion(client.getReplyCode())) {
client.disconnect();
logger.error("FTP server refused connection.");
System.exit(1);
}
client.login("USER FTP", "PASS FTP");
boolean type = client.setFileType(FTP.LOCAL_FILE_TYPE);
logger.info("Tipo Aceptado:" + type);
client.setControlKeepAliveTimeout(300);
client.enterLocalPassiveMode();
if (client.isConnected()) {
FileInputStream fis = null;
fis = new FileInputStream(filelocal);
client.storeFile(filelocal.getName(), fis);
client.logout();
if (fis != null) {
fis.close();
}
}
logger.info(client.getReplyString());
} catch (IOException e) {
logger.error("error" + e.getMessage());
e.printStackTrace();
} catch (Exception e) {
logger.error("error" + e.getMessage());
e.printStackTrace();
}
}

Categories

Resources