How to Determine if FTP Directory Exists
.net, c#, ftp, ftpwebrequest, webrequest
Solution
FTP servers reply with a 550 message when you ask for a non existing directory/file. This 550 is translated to an exception in .NET.
Regarding the code you presented I don't see the reason to use a StreamReader in production. A simple modification is the following:
public bool DirectoryExists(string directory)
{
try
{
FtpWebRequest request = GetRequest(directory);
request.Method = WebRequestMethods.Ftp.ListDirectory;
return request.GetResponse() != null;
}
catch
{
return false;
}
}
I kept the exception handling as is (missing) but I suggest you to work on it as there are many and different cases to catch that are not related to ftp responses.
request.GetResponse() will generate an exception if the directory does not exist.
I tried it with the following paths for true returns:
- ftp://ftp.mozilla.org/
- ftp://ftp.mozilla.org/pub/
- ftp://ftp.mozilla.org/pub/data/
- ftp://ftp.mozilla.org/pub/data/bloat-reports/
The last one is an existing but empty directory
ftp://ftp.mozilla.org/pub/data/bloat-reports2/ returns false
There is a big but regarding trailing / in paths.
mozilla.org is a zero byte length file under pub directory
ftp://ftp.mozilla.org/pub/mozilla.org returns true
ftp://ftp.mozilla.org/pub/mozilla.org/ returned false and then true ?????
This behavior looks like with what you described. You can easily reproduce it on a browser. I suggest you to do the same with your own paths and check the contents of the directories. In case you do have empty files, remove them or replace their contents with a space, and finally check your code to ensure that you will not create new files or recreate them with zero byte length.
I hope that this helps.
UPDATE
No news, bad news! I assume that nothing of the above helped you. Maybe by going one level up in your path will solve the problem. The idea is to get a list of the parent directory and check it for the child name. If the parent path is valid it should always return non empty string. The code is the following:
static bool DirectoryExists(string directory)
{
try
{
directory = GetRequest(directory);
string
parent = directory.Substring(0, directory.TrimEnd('/').LastIndexOf('/') + 1),
child = directory.Substring(directory.TrimEnd('/').LastIndexOf('/') + 1).TrimEnd('/');
FtpWebRequest request = GetRequest(parent);
request.Method = WebRequestMethods.Ftp.ListDirectory;
using (FtpWebResponse response = request.GetResponse() as FtpWebResponse)
{
if (response == null)
return false;
string data = new StreamReader(response.GetResponseStream(), true).ReadToEnd();
return data.IndexOf(child, StringComparison.InvariantCultureIgnoreCase) >= 0;
}
}
catch
{
return false;
}
}
As you can see there is no need to worry about trailing slashes.
Warning: The code will not cover the case of a subdirectory and a filename with same names under the same path.
Problem
I wrote the following code to detect if a directory exists. The `DirectoryExists` method accepts either a fully qualified or relative path. ``` public bool DirectoryExists(string directory) { try { FtpWebRequest request = GetRequest(directory); request.Method = WebRequestMethods.Ftp.ListDirectory; using (FtpWebResponse response = request.GetResponse() as FtpWebResponse) using (StreamReader sr = new StreamReader(response.GetResponseStream(), System.Text.Encoding.ASCII)) { sr.ReadToEnd(); } return true; } catch { } return false; } protected FtpWebRequest GetRequest(string filename = "") { FtpWebRequest request = WebRequest.Create(_host.GetUrl(filename)) as FtpWebRequest; request.Credentials = new NetworkCredential(Username, Password); request.Proxy = null; request.KeepAlive = false; return request; } ``` Note: `_host.GetUrl(filename)` returns the fully qualified path of the specified directory or filename. In my case, this is `ftp://www.mydomain.com/Articles/controls/precisely-defining-kilobytes-megabytes-and-gigabytes`. This code has worked for many months. But all of a sudden it stopped working. Now, there is no exception raised in `DirectoryExists` when the directory does not exist. `sr.ReadToEnd()` simply returns an empty string. I posted a similar question and it was suggested that I should always append `/` to the end of my path. I tried that, and thought I got an exception once, but it's not raising an exception now. I don't know if the behavior changed on the FTP server I'm communicating with or what. Again, this worked fine when I wrote it and now it doesn't. How can I determine whether or not an FTP directory exists? EDIT: Inspecting the response after calling `ReadToEnd()`, I see: BannerMessage="220 Microsoft FTP Service\r\n" ContentLength=-1 ExitMessage="221 Goodbye.\r\n" StatusCode=ClosingData StatusDescription="226 Transfer complete.\r\n" WelcomeMessage="230 User logged in.\r\n" UPDATE: Ultimately, I see that most people have been recommending variations of what I was doing originally. This has lent weight to Hans Passant's suggestion that the issue lies with the server. I am attempting to get them to look at this but they seem a little baffled by the entire discussion. I know they are using a Microsoft server, and I'm skeptical I will be able to get a resolution from them. If all else fails, I think the answer is to do a listing of the parent directory, which does require some extra work to handle cases such as when the directory in question is the root, and also cases when the parent doesn't exist.