Java FTP Download a complete folder from server
- Details
- Written by Nam Ha Minh
- Last Updated on 19 July 2019   |   Print Email
It’s not difficult to write Java code for downloading a single file from a FTP server. However it would be quite complex if we want to download a complete directory because a directory differs greatly from a file, as it may contain sub files and sub directories which can be nested in many levels. In this article, we present a solution for downloading a whole directory from the FTP server, which is tested and proved as working very well.
The solution is based on these two tutorials:
For the sake of reusability, we implement the solution as a utility class looks like this:
public class FTPUtil { public static void downloadDirectory(FTPClient ftpClient, String parentDir, String currentDir, String saveDir) throws IOException { // code to download a directory... } public static boolean downloadSingleFile(FTPClient ftpClient, String remoteFilePath, String savePath) throws IOException { // code to download a file... } }
Here the downloadSingleFile() method is used downloadDirectory() method and can be also used independently to download just a file. Following is the implementation of the downloadSingleFile() method:
/** * Download a single file from the FTP server * @param ftpClient an instance of org.apache.commons.net.ftp.FTPClient class. * @param remoteFilePath path of the file on the server * @param savePath path of directory where the file will be stored * @return true if the file was downloaded successfully, false otherwise * @throws IOException if any network or IO error occurred. */ public static boolean downloadSingleFile(FTPClient ftpClient, String remoteFilePath, String savePath) throws IOException { File downloadFile = new File(savePath); File parentDir = downloadFile.getParentFile(); if (!parentDir.exists()) { parentDir.mkdir(); } OutputStream outputStream = new BufferedOutputStream( new FileOutputStream(downloadFile)); try { ftpClient.setFileType(FTP.BINARY_FILE_TYPE); return ftpClient.retrieveFile(remoteFilePath, outputStream); } catch (IOException ex) { throw ex; } finally { if (outputStream != null) { outputStream.close(); } } }
This method is pretty simple and the Javadoc explains its signature quite well.
And here is the important part - the implementation of the downloadDirectory() method:
/** * Download a whole directory from a FTP server. * @param ftpClient an instance of org.apache.commons.net.ftp.FTPClient class. * @param parentDir Path of the parent directory of the current directory being * downloaded. * @param currentDir Path of the current directory being downloaded. * @param saveDir path of directory where the whole remote directory will be * downloaded and saved. * @throws IOException if any network or IO error occurred. */ public static void downloadDirectory(FTPClient ftpClient, String parentDir, String currentDir, String saveDir) throws IOException { String dirToList = parentDir; if (!currentDir.equals("")) { dirToList += "/" + currentDir; } FTPFile[] subFiles = ftpClient.listFiles(dirToList); if (subFiles != null && subFiles.length > 0) { for (FTPFile aFile : subFiles) { String currentFileName = aFile.getName(); if (currentFileName.equals(".") || currentFileName.equals("..")) { // skip parent directory and the directory itself continue; } String filePath = parentDir + "/" + currentDir + "/" + currentFileName; if (currentDir.equals("")) { filePath = parentDir + "/" + currentFileName; } String newDirPath = saveDir + parentDir + File.separator + currentDir + File.separator + currentFileName; if (currentDir.equals("")) { newDirPath = saveDir + parentDir + File.separator + currentFileName; } if (aFile.isDirectory()) { // create the directory in saveDir File newDir = new File(newDirPath); boolean created = newDir.mkdirs(); if (created) { System.out.println("CREATED the directory: " + newDirPath); } else { System.out.println("COULD NOT create the directory: " + newDirPath); } // download the sub directory downloadDirectory(ftpClient, dirToList, currentFileName, saveDir); } else { // download the file boolean success = downloadSingleFile(ftpClient, filePath, newDirPath); if (success) { System.out.println("DOWNLOADED the file: " + filePath); } else { System.out.println("COULD NOT download the file: " + filePath); } } } } }
This method iterates over all files and sub directories of the current directory in the following manner:
- If the current item is a file, call the method downloadSingleFile() to download that file.
- If the current item is a directory, create that directory in the local computer and call the downloadDirectory() method itself. Repeat the same steps for the sub directory, and sub directory of sub directory, and so on (recursively).
The important point in this method is to re-create directory structure of the remote directory on the local computer correctly. The following example illustrates how to use this method:
FTPClient ftpClient = new FTPClient(); // connect and login... // directory on the server to be downloaded String remoteDirPath = "/MyPhotos"; // directory where the files will be saved String saveDirPath = "D:/Download"; // call the utility method FTPUtil.downloadDirectory(ftpClient, remoteDirPath, "", saveDirPath);
Notice that we always pass an empty String (“”) for the parameter currentDir when calling this method. Only the recursive calls will pass specific values for this parameter.
Now we create a test program as follows:
import java.io.IOException; import org.apache.commons.net.ftp.FTPClient; public class FTPDownloadDirectoryTest { public static void main(String[] args) { String server = "www.codejava.net"; int port = 21; String user = "username"; String pass = "password"; FTPClient ftpClient = new FTPClient(); try { // connect and login to the server ftpClient.connect(server, port); ftpClient.login(user, pass); // use local passive mode to pass firewall ftpClient.enterLocalPassiveMode(); System.out.println("Connected"); String remoteDirPath = "/Test"; String saveDirPath = "E:/Test/Download/FTP"; FTPUtil.downloadDirectory(ftpClient, remoteDirPath, "", saveDirPath); // log out and disconnect from the server ftpClient.logout(); ftpClient.disconnect(); System.out.println("Disconnected"); } catch (IOException ex) { ex.printStackTrace(); } } }
Compile the utility class:
javac -cp commons-net-VERSION.jar FTPUtil.java
Compile the test program:
javac -cp commons-net-VERSION.jar;. FTPDownloadDirectoryTest.java
Run the program:
java -cp commons-net-VERSION.jar;. FTPDownloadDirectoryTest
Assuming that we want to download the directory /Test on the server which has following structure:
Then the test program would produce the following output:
NOTE:You can download the latest distribution of the Apache Commons Net library here.
If you want to download only directory structure, see the article: Download only structure of a directory from FTP server.
Related Java FTP Tutorials:
- Upload only structure of a directory to FTP server
- Java FTP file download tutorial and example
- Use URLConnection to download file from FTP server
Other Java FTP Tutorials:
- Connect and login to a FTP server
- Java FTP create directory example
- Java FTP example - Change working directory
- Java FTP list files and directories example
- Java FTP file upload tutorial and example
- Java FTP delete file example
- Java FTP example - Search for files and directories
Comments
Is there any option to download the files to users "Download" folder in Java ?If so could you please share me with sample code.
Ok let me try. Thank you.
So you need to calculate total size of all files in the directory before downloading. And update the code logic accordingly (you have to think and do some maths).
Hi, but it's only ONE download file, it's different from this case (download multi files at the same time) so I don't know how to do ?
For your reference: codejava.net/.../...