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:
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.
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.