How to Delete a Non-Empty Directory in FTP
The FTP protocol does not allow a directory to be deleted while it still contains files or subdirectories. To delete a non-empty directory, all of its contents must be deleted first, including the contents of any subdirectories, and then the directory itself can be removed.
The FTP component provides the building blocks for this:
- The ChangeRemotePath method changes the current directory on the server.
- The ListDirectoryLong method lists the contents of the current directory, and populates the DirList collection. Each entry's IsDir field indicates whether it is a directory.
- The DeleteFile method deletes a file, and the RemoveDirectory method removes an empty directory. Both accept either an absolute path or a path relative to the current directory.
Deleting a Directory Recursively
The helper method below deletes a directory and everything in it. It lists the directory, deletes each file, calls itself for each subdirectory, and finally removes the directory once it is empty.
void DeleteDirectory(FTP ftp, string path) {
// List the contents of the directory.
ftp.ChangeRemotePath(path);
ftp.RemoteFile = ""; // Clear any file mask, so that the whole directory is listed.
ftp.ListDirectoryLong();
// Copy the listing, since listing a subdirectory replaces the contents of the DirList collection.
List<string> files = new List<string>();
List<string> subdirectories = new List<string>();
foreach (DirEntry entry in ftp.DirList) {
// Some servers include entries for the current and parent directories.
if (entry.FileName == "." || entry.FileName == "..") continue;
if (entry.IsDir) subdirectories.Add(entry.FileName);
else files.Add(entry.FileName);
}
// Delete the files in the directory.
foreach (string file in files) {
ftp.DeleteFile(path + "/" + file);
}
// Delete each subdirectory and its contents.
foreach (string subdirectory in subdirectories) {
DeleteDirectory(ftp, path + "/" + subdirectory);
}
// Leave the directory before removing it, since some servers do not allow the current directory to be removed.
ftp.ChangeRemotePath("/");
ftp.RemoveDirectory(path);
}
To use the helper, log on to the server and pass it the absolute path of the directory to delete.
FTP ftp = new FTP();
ftp.RemoteHost = "ftp.example.com";
ftp.User = "USER";
ftp.Password = "PASSWORD";
ftp.Logon();
DeleteDirectory(ftp, "/uploads/old-reports");
ftp.Logoff();
The same approach works for FTPS (FTP over TLS), which is supported by the FTP component through the SSLStartMode property.
Notes
- ListDirectoryLong treats the RemoteFile property as a file mask, and the DeleteFile and RemoveDirectory methods set RemoteFile to the name passed to them. This is why the helper clears RemoteFile before each listing.
- Deleting a directory recursively cannot be undone. Make sure the path is correct before calling the helper, and consider listing the contents first to confirm what will be deleted.
- If any file or directory cannot be deleted (e.g., due to permissions), the component throws an exception and the helper stops. Already-deleted files are not restored.
- Symbolic links are reported as files (with IsDir set to false), so the helper deletes the link itself rather than the contents of the directory it points to.
- The helper assumes the default directory listing format. If the UseMLSD configuration setting is enabled, the listing may also include entries for the current and parent directories (which may not be named . and ..), and these must be skipped as well.
Note that in older versions of IPWorks, the current directory was set using the RemotePath property, which has been replaced by the ChangeRemotePath and QueryRemotePath methods.
We appreciate your feedback. If you have any questions, comments, or suggestions about this article please contact our support team at support@nsoftware.com.