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.
Nam Ha Minh is certified Java programmer (SCJP and SCWCD). He began programming with Java back in the days of Java 1.4 and has been passionate about it ever since. You can connect with him on Facebook and watch his Java videos on YouTube.