How to check if an FTP directory exists
Asked Answered
P

11

35

Looking for the best way to check for a given directory via FTP.

Currently i have the following code:

private bool FtpDirectoryExists(string directory, string username, string password)
{

    try
    {
        var request = (FtpWebRequest)WebRequest.Create(directory);
        request.Credentials = new NetworkCredential(username, password);
        request.Method = WebRequestMethods.Ftp.GetDateTimestamp;

        FtpWebResponse response = (FtpWebResponse)request.GetResponse();
    }
    catch (WebException ex)
    {
        FtpWebResponse response = (FtpWebResponse)ex.Response;
        if (response.StatusCode == FtpStatusCode.ActionNotTakenFileUnavailable)
            return false;
        else
            return true;
    }
    return true;
}

This returns false whether the directory is there or not. Can someone point me in the right direction.

Platform answered 4/5, 2010 at 21:35 Comment(0)
P
21

Basically trapped the error that i receive when creating the directory like so.

private bool CreateFTPDirectory(string directory) {

    try
    {
        //create the directory
        FtpWebRequest requestDir = (FtpWebRequest)FtpWebRequest.Create(new Uri(directory));
        requestDir.Method = WebRequestMethods.Ftp.MakeDirectory;
        requestDir.Credentials = new NetworkCredential("username", "password");
        requestDir.UsePassive = true;
        requestDir.UseBinary = true;
        requestDir.KeepAlive = false;
        FtpWebResponse response = (FtpWebResponse)requestDir.GetResponse();
        Stream ftpStream = response.GetResponseStream();

        ftpStream.Close();
        response.Close();

        return true;
    }
    catch (WebException ex)
    {
        FtpWebResponse response = (FtpWebResponse)ex.Response;
        if (response.StatusCode == FtpStatusCode.ActionNotTakenFileUnavailable)
        {
            response.Close();
            return true;
        }
        else
        {
            response.Close();
            return false;
        }  
    }
}
Platform answered 7/5, 2010 at 21:43 Comment(2)
This code is unreliable: for example if you have not write rights and there's no desired directory this function will return true.Conium
There is the option of also checking the StatusDescription property of the FtpWebResponse. If it contains 'exists' (550 Directory already exists) then it already exists. HOWEVER I haven't found any spec or reassurance that all FTP servers must return that, it may just be the case with FileZilla. So test it in your particural scenario and decide if it's something you want to do / risk.Andyane
P
17

The complete solution will now be:

public bool DoesFtpDirectoryExist(string dirPath)
{
    try
    {
        FtpWebRequest request = (FtpWebRequest)WebRequest.Create(dirPath);  
        request.Method = WebRequestMethods.Ftp.ListDirectory;  
        FtpWebResponse response = (FtpWebResponse)request.GetResponse();
        return true;
     }
     catch(WebException ex)
     {
         return false;
     }
}

// Calling the method (note the forwardslash at the end of the path):
string ftpDirectory = "ftp://ftpserver.com/rootdir/test_if_exist_directory/";
bool dirExists = DoesFtpDirectoryExist(ftpDirectory);

Originally, I was using,

string ftpDirectory = "ftp://ftpserver.com/rootdir/test_if_exist_directory";
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(ftpDirectory);  
request.Method = WebRequestMethods.Ftp.ListDirectory;  
FtpWebResponse response = (FtpWebResponse)request.GetResponse();

and waited for an exception in case the directory didn't exist. This method didn't throw an exception.

After a few hit and trials, I changed the directory from:

ftp://ftpserver.com/rootdir/test_if_exist_directory

to:

ftp://ftpserver.com/rootdir/test_if_exist_directory/

Now the code is working for me.

I think we should append a forward slash (/) to the URI of the FTP folder to get it to work.

Powered answered 4/6, 2014 at 21:33 Comment(2)
Cannot a WebException indicate other errors than a missing directory? I suggest that you test wheter its StatusCode equals FtpStatusCode.ActionNotTakenFileUnavailable, and report an error if does not.Overflight
The slash indeed matters: Why does FtpWebRequest return an empty stream for this existing directory?.Acupuncture
V
9

I assume that you are already somewhat familiar with FtpWebRequest, as this is the usual way to access FTP in .NET.

You can attempt to list the directory and check for an error StatusCode.

try 
{  
    FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://ftp.microsoft.com/12345");  
    request.Method = WebRequestMethods.Ftp.ListDirectory;  
    using (FtpWebResponse response = (FtpWebResponse)request.GetResponse())  
    {  
        // Okay.  
    }  
}  
catch (WebException ex)  
{  
    if (ex.Response != null)  
    {  
        FtpWebResponse response = (FtpWebResponse)ex.Response;  
        if (response.StatusCode == FtpStatusCode.ActionNotTakenFileUnavailable)  
        {  
            // Directory not found.  
        }  
    }  
} 
Velazquez answered 20/8, 2012 at 16:15 Comment(2)
I have found this to be unreliable. I have a case where no exception is thrown when the specified directory does not exist.Christo
The URL has to end with a slash for the code to work reliably: Why does FtpWebRequest return an empty stream for this existing directory?.Acupuncture
C
8

I would try something along this lines:

  • Send MLST <directory> FTP command (defined in RFC3659) and parse it's output. It should return valid line with directory details for existing directories.

  • If MLST command is not available, try changing the working directory into the tested directory using a CWD command. Don't forget to determine the current path (PWD command) prior to changing to a tested directory to be able to go back.

  • On some servers combination of MDTM and SIZE command can be used for similar purpose, but the behavior is quite complex and out of scope of this post.

This is basically what DirectoryExists method in the current version of our Rebex FTP component does. The following code shows how to use it:

string path = "/path/to/directory";

Rebex.Net.Ftp ftp = new Rebex.Net.Ftp();
ftp.Connect("hostname");
ftp.Login("username","password");

Console.WriteLine(
  "Directory '{0}' exists: {1}", 
  path, 
  ftp.DirectoryExists(path)
);

ftp.Disconnect();
Casey answered 17/12, 2010 at 16:33 Comment(1)
Although the other answers provide code, they essentially are creating a new directory to see if an error occurs. Much better to simply issue the FTP 'CWD' command to which the server will issue a 5xx reply code if the directory does not exist.Galba
H
4

User this code it may be your answer..

 public bool FtpDirectoryExists(string directoryPath, string ftpUser, string ftpPassword)
        {
            bool IsExists = true;
            try
            {
                FtpWebRequest request = (FtpWebRequest)WebRequest.Create(directoryPath);
                request.Credentials = new NetworkCredential(ftpUser, ftpPassword);
                request.Method = WebRequestMethods.Ftp.PrintWorkingDirectory;

                FtpWebResponse response = (FtpWebResponse)request.GetResponse();
            }
            catch (WebException ex)
            {
                IsExists = false;
            }
            return IsExists;
        }

I have called this method as:

bool result =    FtpActions.Default.FtpDirectoryExists( @"ftp://mydomain.com/abcdir", txtUsername.Text, txtPassword.Text);

Why use another library - create your own logic's.

Heath answered 20/7, 2011 at 10:44 Comment(1)
This will only return the CWD (Current Working Directory). No mater what you append to the host address (ex: mydomain.com) it will always return the current directory another words IsExists would never be anything other then true. If this is the only thing I do (above) then on my server it simply shows "257 '/' is current directory.". Not "257 '/abcdir/' is current directory." like everyone would expect.Hinds
T
2

I tried every which way to get a solid check but neither the WebRequestMethods.Ftp.PrintWorkingDirectory nor WebRequestMethods.Ftp.ListDirectory methods would work correctly. They failed when checking for ftp://<website>/Logs which doesnt exist on the server but they say it does.

So the method I came up with was to try to upload to the folder. However, one 'gotcha' is the path format which you can read about in this thread Uploading to Linux

Here is a code snippet

private bool DirectoryExists(string d) 
{ 
    bool exists = true; 
    try 
    { 
        string file = "directoryexists.test"; 
        string path = url + homepath + d + "/" + file;
        //eg ftp://website//home/directory1/directoryexists.test
        //Note the double space before the home is not a mistake

        //Try to save to the directory 
        req = (FtpWebRequest)WebRequest.Create(path); 
        req.ConnectionGroupName = "conngroup1"; 
        req.Method = WebRequestMethods.Ftp.UploadFile; 
        if (nc != null) req.Credentials = nc; 
        if (cbSSL.Checked) req.EnableSsl = true; 
        req.Timeout = 10000; 

        byte[] fileContents = System.Text.Encoding.Unicode.GetBytes("SAFE TO DELETE"); 
        req.ContentLength = fileContents.Length; 

        Stream s = req.GetRequestStream(); 
        s.Write(fileContents, 0, fileContents.Length); 
        s.Close(); 

        //Delete file if successful 
        req = (FtpWebRequest)WebRequest.Create(path); 
        req.ConnectionGroupName = "conngroup1"; 
        req.Method = WebRequestMethods.Ftp.DeleteFile; 
        if (nc != null) req.Credentials = nc; 
        if (cbSSL.Checked) req.EnableSsl = true; 
        req.Timeout = 10000; 

        res = (FtpWebResponse)req.GetResponse(); 
        res.Close(); 
    } 
    catch (WebException ex) 
    { 
        exists = false; 
    } 
    return exists; 
} 
Task answered 2/11, 2011 at 16:48 Comment(0)
O
0

Navigate to the parent directory, execute the "ls" command, and parse the result.

Ornithopod answered 4/5, 2010 at 21:38 Comment(1)
But if the parent directory does not exists, it does return error status 550.Brynnbrynna
A
0

I couldn't get this @BillyLogans suggestion to work....

I found the problem was the default FTP directory was /home/usr/fred

When I used:

String directory = "ftp://some.domain.com/mydirectory"
FtpWebRequest requestDir = (FtpWebRequest)FtpWebRequest.Create(new Uri(directory));

I found this gets turned into

"ftp:/some.domain.com/home/usr/fred/mydirectory"

to stop this change the directory Uri to:

String directory = "ftp://some.domain.com//mydirectory"

Then this starts working.

Anthonyanthophore answered 24/9, 2010 at 17:4 Comment(1)
B
-1

This was my best. get list from parent dir, and check if parent have correct child name

public void TryConnectFtp(string ftpPath)
        {
            string[] splited = ftpPath.Split('/');
            StringBuilder stb = new StringBuilder();
            for (int i = 0; i < splited.Length - 1; i++)
            {
                stb.Append(splited[i] +'/');
            }
            string parent = stb.ToString();
            string child = splited.Last();

            FtpWebRequest testConnect = (FtpWebRequest)WebRequest.Create(parent);
            testConnect.Method = WebRequestMethods.Ftp.ListDirectory;
            testConnect.Credentials = credentials;
            using (FtpWebResponse resFtp = (FtpWebResponse)testConnect.GetResponse())
            {
                StreamReader reader = new StreamReader(resFtp.GetResponseStream());
                string result = reader.ReadToEnd();
                if (!result.Contains(child) ) throw new Exception("@@@");

                resFtp.Close();
            }
        }
Backer answered 5/2, 2021 at 8:45 Comment(0)
B
-3

The only way which worked for me was an inversed logic by trying to create the directory/path (which will throw an exception if it already exists) and if so delete it again afterwards. Otherwise use the Exception to set a flag meaing that the directory/path exists. I'm quite new to VB.NET and I'm shure there's a nicer way to code this - but anyway here's my code:

        Public Function DirectoryExists(directory As String) As Boolean
        ' Reversed Logic to check if a Directory exists on FTP-Server by creating the Directory/Path
        ' which will throw an exception if the Directory already exists. Otherwise create and delete the Directory

        ' Adjust Paths
        Dim path As String
        If directory.Contains("/") Then
            path = AdjustDir(directory)     'ensure that path starts with a slash
        Else
            path = directory
        End If

        ' Set URI (formatted as ftp://host.xxx/path)

        Dim URI As String = Me.Hostname & path

        Dim response As FtpWebResponse

        Dim DirExists As Boolean = False
        Try
            Dim request As FtpWebRequest = DirectCast(WebRequest.Create(URI), FtpWebRequest)
            request.Credentials = Me.GetCredentials
            'Create Directory - if it exists WebException will be thrown
            request.Method = WebRequestMethods.Ftp.MakeDirectory

            'Delete Directory again - if above request did not throw an exception
            response = DirectCast(request.GetResponse(), FtpWebResponse)
            request = DirectCast(WebRequest.Create(URI), FtpWebRequest)
            request.Credentials = Me.GetCredentials
            request.Method = WebRequestMethods.Ftp.RemoveDirectory
            response = DirectCast(request.GetResponse(), FtpWebResponse)
            DirExists = False

        Catch ex As WebException
            DirExists = True
        End Try
        Return DirExists

    End Function

WebRequestMethods.Ftp.MakeDirectory and WebRequestMethods.Ftp.RemoveDirectory are the Methods i used for this. All other solutions did not work for me.

Hope it helps

Blaylock answered 8/5, 2016 at 18:57 Comment(0)
H
-5

For what it is worth, You'll make your FTP life quite a bit easier if you use EnterpriseDT's FTP component. It's free and will save you headaches because it deals with the commands and responses. You just work with a nice, simple object.

Heading answered 4/5, 2010 at 21:48 Comment(1)
I'm not adding to the downvotes since things may have changed since the original post, but fwiw the component is no longer free.Viguerie

© 2022 - 2024 — McMap. All rights reserved.