With the help of Apache Commons Net API, it is easy to write Java code for downloading a file from a remote FTP server to local computer. In this article, you will learn how to properly implement Java code to get files downloaded from a server via FTP protocol. A working sample program also provided.

Table of Content

    1. Apache Commons Net API for downloading files by FTP protocol
    2. The proper steps to download a file
    3. Sample program code
    4. Compile and run the sample program

 

1. Apache Commons Net API for downloading files by FTP protocol

 The org.apache.commons.net.ftp.FTPClient class provides two methods for downloading files from a FTP server:

    • boolean retrieveFile(String remote, OutputStream local): This method retrieves a remote file whose path is specified by the parameter remote, and writes it to the OutputStream specified by the parameter local. The method returns true if operation completed successfully, or false otherwise. This method is suitable in case we don’t care how the file is written to disk, just let the system use the given OutputStream to write the file. We should close OutputStream the after the method returns.
    • InputStream retrieveFileStream(String remote): This method does not use an OutputStream, instead it returns an InputStreamwhich we can use to read bytes from the remote file. This method gives us more control on how to read and write the data. But there are two important points when using this method:
      • The method completePendingCommand() must be called afterward to finalize file transfer and check its return value to verify if the download is actually done successfully.
      • We must close the InputStream explicitly.

Learn about Technology Today!Which method is used suitable for you? Here are few tips:

    • The first method provides the simplest way for downloading a remote file, as just passing an OutputStream of the file will be written on disk.
    • The second method requires more code to be written, as we have to create a new OutputStream for writing file’s content while reading its byte arrays from the returned InputStream. This method is useful when we want to measure progress of the download, i.e. how many percentages of the file have been transferred. In addition, we have to call the completePendingCommand()to finalize the download.
    • Both the methods throw an IOException exception (or one of its descendants, FTPConnectionClosedException and CopyStreamException). Therefore, make sure to handle these exceptions when calling the methods.

In addition, the following two methods must be invoked before calling the retrieveFile() and retrieveFileStream() methods:

    • void enterLocalPassiveMode(): this method switches data connection mode from server-to-client (default mode) to client-to-server which can pass through firewall. There might be some connection issues if this method is not invoked.
    • boolean setFileType(int fileType) : this method sets file type to be transferred, either as ASCII text file or binary file. It is recommended to set file type to FTP.BINARY_FILE_TYPE, rather than FTP.ASCII_FILE_TYPE.

 

2. The proper steps to download a file

 Here are the steps to properly implement code for downloading a remote file from a FTP server using Apache Commons Net API which is discussed so far:

    •           Connect and login to the server.
    •           Enter local passive mode for data connection.
    •           Set file type to be transferred to binary.
    •           Construct path of the remote file to be downloaded.
    •           Create a new OutputStream for writing the file to disk.
    •           If using the first method (retrieveFile):
      •    Pass the remote file path and the OutputStream as arguments of the method retrieveFile().
      •      Close the OutputStream.
      •      Check return value of retrieveFile() to verify success.
    •           If using the second method (retrieveFileStream):
      •      Retrieve an InputStream returned by the method retrieveFileStream().
      •      Repeatedly a byte array from the InputStream and write these bytes into the OutputStream, until the InputStream is empty.
      •      Call completePendingCommand() method to complete transaction.
      •      Close the opened OutputStream the InputStream.
      •      Check return value of completePendingCommand() to verify success.
    •           Logout and disconnect from the server.

 

3. Sample program code

In the following sample program, using both methods is implemented for transferring a file from the FTP server to local computer. Here is the program’s source code:

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;

/**
 * A program demonstrates how to upload files from local computer to a remote
 * FTP server using Apache Commons Net API.
 * @author www.codejava.net
 */
public class FTPDownloadFileDemo {

	public static void main(String[] args) {
		String server = "www.myserver.com";
		int port = 21;
		String user = "user";
		String pass = "pass";

		FTPClient ftpClient = new FTPClient();
		try {

			ftpClient.connect(server, port);
			ftpClient.login(user, pass);
			ftpClient.enterLocalPassiveMode();
			ftpClient.setFileType(FTP.BINARY_FILE_TYPE);

			// APPROACH #1: using retrieveFile(String, OutputStream)
			String remoteFile1 = "/test/video.mp4";
			File downloadFile1 = new File("D:/Downloads/video.mp4");
			OutputStream outputStream1 = new BufferedOutputStream(new FileOutputStream(downloadFile1));
			boolean success = ftpClient.retrieveFile(remoteFile1, outputStream1);
			outputStream1.close();

			if (success) {
				System.out.println("File #1 has been downloaded successfully.");
			}

			// APPROACH #2: using InputStream retrieveFileStream(String)
	        String remoteFile2 = "/test/song.mp3";
	        File downloadFile2 = new File("D:/Downloads/song.mp3");
	        OutputStream outputStream2 = new BufferedOutputStream(new FileOutputStream(downloadFile2));
	        InputStream inputStream = ftpClient.retrieveFileStream(remoteFile2);
	        byte[] bytesArray = new byte[4096];
	        int bytesRead = -1;
	        while ((bytesRead = inputStream.read(bytesArray)) != -1) {
	        	outputStream2.write(bytesArray, 0, bytesRead);
	        }

	        success = ftpClient.completePendingCommand();
			if (success) {
				System.out.println("File #2 has been downloaded successfully.");
			}
			outputStream2.close();
			inputStream.close();

		} catch (IOException ex) {
			System.out.println("Error: " + ex.getMessage());
			ex.printStackTrace();
		} finally {
			try {
				if (ftpClient.isConnected()) {
					ftpClient.logout();
					ftpClient.disconnect();
				}
			} catch (IOException ex) {
				ex.printStackTrace();
			}
		}
	}
}

 

 

4. Compile and run the sample program

To compile and run the program, you need an Apache Commons Net’s jar library file presented in the classpath. Click here to download the latest distribution of Apache Commons Net.

Extract the distribution zip file and copy the commons-net-VERSION.jar file into the same folder of the FTPDownloadFileDemo.java file.

Type the following command to compile the program:

javac –cp commons-net-VERSION.jar FTPDownloadFileDemo.java

And type this command to run the program:

java –cp commons-net-VERSION.jar;. FTPDownloadFileDemo

 

 

NOTES:

Recommended books:
Attachments:
Download this file (FTPDownloadFileDemo.java)FTPDownloadFileDemo.java[Java FTP File Download Program]2 kB
avatar
Hello,

I am trying to download ZIP file (244 KB) which i have uploaded on FTP server using Apache library 3.3 with Approach #2 code for uploading and downloading.

I have set defaultTimeout 1200 before ftp connection made.
I got SocketTimeout issue when downloading happens.

please provide your feedback on the same to resolve downloading problem of SocketTimeout exception.

Looking for your cooperation and quick response.
VOTES:0
avatar
Hi Durgesh,

Although the data channel is still active, the control channel may be not. So you can call:

ftpClient.setControlKeepAliveTimeout(300);

to cause the client sends a NOOP command after every 300 seconds to avoid timeout happens on the control channel.
VOTES:0
avatar
Hi Guys, my download using retrieveFileStream and after all bytes read, it get stuck at completePendingCommand function.
I did exactly as the sample code. The code works for files less than 250MB. But larger file it for sure get stucked.
My FTP Server is almost never timeout.

Need help here!
VOTES:0
avatar
Hi George,


Did you call this statement:


ftpClient.setControlKeepAliveTimeout(300);


Because the data channel won't be timed out, but the control channel will be.
VOTES:0
avatar
Hi All,

I want to test simple FTP programs in my local windows machine without having the real (Physical) FTP server. is there any way we can achieve it ?

Thanks for your time in advance.
Harsh.


VOTES:0
avatar
Hi Harsh Mehta,
You can you Filezilla as a FTP server on your local computer.
VOTES:0
avatar
Same code i have user, but getting below lock excletion, Any idea why we are getting this issue.
Can you please help me with this.

Application [34]" cpu=23080.00 [reset 160.00] ms allocated=1876879112 B (1.75 GB) [reset 32370624 B (30.87 MB)] defined_classes=46
io= file i/o: 98011/105696 B, net i/o: 32050693/39855301 B, files opened:78, socks opened:168 [reset file i/o: 0/2698 B, net i/o: 2629274/2703340 B, files opened:1, socks opened:22 ]
user="" request="50917" application="bc-qm~ear_service_mgt" prio=10 tid=0x00002abcd00b3440 nid=0x3d37 / 15671 pthread-id=46990491285824 runnable [_thread_in_native (_at_safepoint), stack(0x00002abcd37a7000,0x00002abcd38a8000)] [0x00002abcd38a4000]
java.lang.Thread.State: RUNNABLE
at java.net.PlainSocketImpl.socketAccept(Ljava/net/SocketImpl;)V(Native Method)
at java.net.PlainSocketImpl.accept(Ljava/net/SocketImpl;)V(PlainSocketImpl.java:408)
- locked <0x0000000084f0a500> (a java.net.SocksSocketImpl)
at java.net.ServerSocket.implAccept(Ljava/net/Socket;)V(ServerSocket.java:462)
at java.net.ServerSocket.accept()Ljava/net/Socket;(ServerSocket.java:430)
at org.apache.commons.net.ftp.FTPClient._openDataConnection_(Ljava/lang/String;Ljava/lang/String;)Ljava/net/Socket;(FTPClient.java:729)
at org.apache.commons.net.ftp.FTPClient._retrieveFile(Ljava/lang/String;Ljava/lang/String;Ljava/io/OutputStream;)Z(FTPClient.java:1677)
VOTES:0
avatar
Hmm, totally no idea.
Did you try with different servers? Maybe only a server causes that problem.
VOTES:0
avatar
hi, I am using exactly the same code than approach #1, but I takes too much time (more than 5 seconds for a 2KB). Do you have any proposal to fix it? Thanks in adavance for your response! Pablo
VOTES:0
avatar
Pablo wrote:
hi, I am using exactly the same code than approach #1, but I takes too much time (more than 5 seconds for a 2KB). Do you have any proposal to fix it? Thanks in adavance for your response! Pablo
hi Pablo, is the second approach faster? Try to increase the buffer size by calling setSendBufferSize(int size).
VOTES:0
Start learning on Udemy today!