How to transfer multiple files and directories

edtFTPj/PRO is able to download, upload and delete multiple files and directories in a single method call.

These capabilities are not available in FTPClient but are in SSLFTPClient, SSHFTPClient and ProFTPClient.

There are four main methods available (with overloads). The relevant methods are listed in the table below:

Method Description
mdelete Deletes files matching the supplied FileFilter or wildcard. If a directory name is not supplied, deletes all matching files in the current directory. If a directory name is supplied, deletes all matching files in the named directory, and optionally in subdirectories (if the recurse flag is true). This method never deletes directories themselves, just files.
mget Downloads files matching the supplied FileFilter or wildcard into the named local directory (which is placed in the current directory). If the recurse flag is true, gets matching files in subdirectories.
mput Uploads files matching the supplied FileFilter or wildcard from the named local directory. If a remote directory name is not supplied, files go into the current remote directory. If a remote directory name is supplied, files go into a remote directory of that name (which itself is in the current remote directory). If the recurse flag is true, all matching files in subdirectories are uploaded as well. Subdirectories that don't exist on the server are created.
rmdir Deletes the named remote directory. If the recurse flag is true, deletes all files and subdirectories. If the recurse flag is false, deletes the named directory (but only if it is empty).

Note that all remote directories should generally be directory names, not paths. Many FTP servers cannot cope with directory paths, and the most portable code is to use directory names. This means that code to put an entire directory should navigate to the parent directory on the server, and then use mput to put the directory. Local directories can be specified as paths.

Files can be matched by FileFilter or wildcard. The wildcard argument is a string that may contain markers for unknown characters. The question-mark (?) character matches a single unknown character. The asterisk (*) character matches one or more unknown character. For example, the wildcard "file*.dat" would match the following strings, "file1.dat", "file10.dat", "fileA.dat", and "fileABC.dat", whereas the wildcard "file?.dat" would match the following strings, "file1.dat" and "fileA.dat", but not "file10.dat" and "fileABC.dat". A FileFilter is a standard java.io.FileFilter implementation - see the Sun Java documentation for more details.

Socket creation problems

When transferring multiple files, it is common to encounter IOExceptions caused by failure to create data sockets. Generally, applications have a limit to the number of sockets they can have open simultaneously (in Unix this is controlled via ulimit). This wouldn't be a problem if sockets disappeared as soon as they were closed. In TCP/IP, however, when sockets are closed they enter the TIME_WAIT state. The socket stays in this state long enough to let stray TCP packets for this connection expire - usually up to 2 minutes. Since every data transfer and directory listing in FTP uses a new socket, if a large number of transfers are performed quickly, the number of sockets in TIME_WAIT can build up rapidly and the application run out of sockets.

One way of minimizing this problem is to slow down the transfer rate. This can be done by sleeping briefly after a certain number of transfers. The API provides a simple mechanism to do this for directory transfers. The setCountBeforeSleep method sets the number of file transfers permitted before the thread calls sleep. The setSleepTime method sets the sleep time (in seconds), while setSleepEnabled enables or disables sleeping. For example:

ftp.setCountBeforeSleep(50); // 50 transfers before sleeping
ftp.setSleepTime(30); // sleep for 30 seconds

API examples

Code Description
ftp.mdelete("*.txt") All the files matching *.txt in the current remote directory are deleted.
ftp.mdelete("test", "*.txt", false) All the files matching *.txt in the remote directory called "test" (no subdirectories) are deleted.
ftp.mdelete("test", "*.txt", true) All the files matching *.txt in the remote directory called "test" (including subdirectories) are deleted.
ftp.mget("D:\\Downloads\\test", "*.txt") All the files matching *.txt in the current remote directory are downloaded into "D:\Downloads\test".
ftp.mget("D:\\Downloads\\test", "test", "*.txt") All the files matching *.txt in the remote directory called "test" (no subdirectories) are downloaded into "D:\Downloads\test".
ftp.mget("D:\\Downloads\\test", "test", "*.txt", true) All the files matching *.txt in the remote directory called "test" (including subdirectories) are downloaded into "D:\Downloads\test".
ftp.mput("D:\\Downloads\\test","*.txt") All the files matching *.txt in the local directory called "D:\Uploads\test" are uploaded into the current remote directory.
ftp.mput("D:\\Downloads\\test","test", "*.txt", false) All the files matching *.txt in the local directory called "D:\Uploads\test" are uploaded into a remote directory called "test" created (if it does not exist) in the current remote directory. No files in subdirectories are uploaded.
ftp.mput("D:\\Downloads\\test","test", "*.txt", true) All the files matching *.txt in the local directory called "D:\Uploads\test" and all its subdirectories are uploaded into a remote directory called "test" created (if it does not exist) in the current remote directory. Remote subdirectories are also created if they don't exist.
ftp.rmdir("test", true) Deletes the remote directory "test" in the current remote directory. Deletes all subdirectories and files. Use with caution!