Uploading a single file to a FTP server is not a tricky thing. However, uploading a whole directory is a different story, as it requires some extra work and effort:
In other words, uploading a directory is similar to copy a directory from the local computer to the FTP server, keeping the copied directory’s structure as same as the original one. Here’s the algorithm we’d like to suggest:
To implement the algorithm above, create a utility class looks like this:
public class FTPUtil { public static void uploadDiretory() throws IOException { // code to upload a whole directory... } public static boolean uploadSingleFile() throws IOException { // code to upload a single file to the server... } }
Following is the detailed implementation of the uploadDirectory() method:
/** * Upload a whole directory (including its nested sub directories and files) * to a FTP server. * * @param ftpClient * an instance of org.apache.commons.net.ftp.FTPClient class. * @param remoteDirPath * Path of the destination directory on the server. * @param localParentDir * Path of the local directory being uploaded. * @param remoteParentDir * Path of the parent directory of the current directory on the * server (used by recursive calls). * @throws IOException * if any network or IO error occurred. */ public static void uploadDirectory(FTPClient ftpClient, String remoteDirPath, String localParentDir, String remoteParentDir) throws IOException { System.out.println("LISTING directory: " + localParentDir); File localDir = new File(localParentDir); File[] subFiles = localDir.listFiles(); if (subFiles != null && subFiles.length > 0) { for (File item : subFiles) { String remoteFilePath = remoteDirPath + "/" + remoteParentDir + "/" + item.getName(); if (remoteParentDir.equals("")) { remoteFilePath = remoteDirPath + "/" + item.getName(); } if (item.isFile()) { // upload the file String localFilePath = item.getAbsolutePath(); System.out.println("About to upload the file: " + localFilePath); boolean uploaded = uploadSingleFile(ftpClient, localFilePath, remoteFilePath); if (uploaded) { System.out.println("UPLOADED a file to: " + remoteFilePath); } else { System.out.println("COULD NOT upload the file: " + localFilePath); } } else { // create directory on the server boolean created = ftpClient.makeDirectory(remoteFilePath); if (created) { System.out.println("CREATED the directory: " + remoteFilePath); } else { System.out.println("COULD NOT create the directory: " + remoteFilePath); } // upload the sub directory String parent = remoteParentDir + "/" + item.getName(); if (remoteParentDir.equals("")) { parent = item.getName(); } localParentDir = item.getAbsolutePath(); uploadDirectory(ftpClient, remoteDirPath, localParentDir, parent); } } } }
And here is the detailed implementation of the uploadSingleFile() method:
/** * Upload a single file to the FTP server. * * @param ftpClient * an instance of org.apache.commons.net.ftp.FTPClient class. * @param localFilePath * Path of the file on local computer * @param remoteFilePath * Path of the file on remote the server * @return true if the file was uploaded successfully, false otherwise * @throws IOException * if any network or IO error occurred. */ public static boolean uploadSingleFile(FTPClient ftpClient, String localFilePath, String remoteFilePath) throws IOException { File localFile = new File(localFilePath); InputStream inputStream = new FileInputStream(localFile); try { ftpClient.setFileType(FTP.BINARY_FILE_TYPE); return ftpClient.storeFile(remoteFilePath, inputStream); } finally { inputStream.close(); } }
In order to use the above utility class, we create a test program as follows:
import java.io.IOException; import org.apache.commons.net.ftp.FTPClient; /** * This test program illustrates how to utilize the FTPUtil class in order * to upload a whole directory to a FTP server. * @author www.codejava.net * */ public class FTPUploadDirectoryTest { 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 = "/Upload"; String localDirPath = "E:/Test/Download/FTP/Test"; FTPUtil.uploadDirectory(ftpClient, remoteDirPath, localDirPath, ""); // log out and disconnect from the server ftpClient.logout(); ftpClient.disconnect(); System.out.println("Disconnected"); } catch (IOException ex) { ex.printStackTrace(); } } }
Supposing you put the Apache Commons Net library jar file into the same directory of the source files, type the following command to compile the utility class and the test program:
javac -cp commons-net-3.6.jar;. FTPUploadDirectoryTest.java
That will also compile the FTPUtil.java file because it is used by the FTPUploadDirectoryTest class.
Type the following command to run the test program:
java -cp commons-net-3.6.jar;. FTPUploadDirectoryTest
If the directory being uploaded E:/Test/Download/FTP/Test has the following structure:
Then the test program will produce the following output:
NOTES: