How to check if file exists on FTP before FtpWebRequest

C#.NetFtpFtpwebrequest

C# Problem Overview


I need to use FtpWebRequest to put a file in a FTP directory. Before the upload, I would first like to know if this file exists.

What method or property should I use to check if this file exists?

C# Solutions


Solution 1 - C#

var request = (FtpWebRequest)WebRequest.Create
    ("ftp://ftp.domain.com/doesntexist.txt");
request.Credentials = new NetworkCredential("user", "pass");
request.Method = WebRequestMethods.Ftp.GetFileSize;

try
{
    FtpWebResponse response = (FtpWebResponse)request.GetResponse();
}
catch (WebException ex)
{
    FtpWebResponse response = (FtpWebResponse)ex.Response;
    if (response.StatusCode ==
        FtpStatusCode.ActionNotTakenFileUnavailable)
    {
        //Does not exist
    }
}

As a general rule it's a bad idea to use Exceptions for functionality in your code like this, however in this instance I believe it's a win for pragmatism. Calling list on the directory has the potential to be FAR more inefficient than using exceptions in this way.

If you're not, just be aware it's not good practice!

EDIT: "It works for me!"

This appears to work on most ftp servers but not all. Some servers require sending "TYPE I" before the SIZE command will work. One would have thought that the problem should be solved as follows:

request.UseBinary = true;

Unfortunately it is a by design limitation (big fat bug!) that unless FtpWebRequest is either downloading or uploading a file it will NOT send "TYPE I". See discussion and Microsoft response here.

I'd recommend using the following WebRequestMethod instead, this works for me on all servers I tested, even ones which would not return a file size.

WebRequestMethods.Ftp.GetDateTimestamp

Solution 2 - C#

Because

request.Method = WebRequestMethods.Ftp.GetFileSize

may fails in some case (550: SIZE not allowed in ASCII mode), you can just check Timestamp instead.

reqFTP.Credentials = new NetworkCredential(inf.LogOn, inf.Password);
reqFTP.UseBinary = true;
reqFTP.Method = WebRequestMethods.Ftp.GetDateTimestamp;

Solution 3 - C#

FtpWebRequest (nor any other class in .NET) does not have any explicit method to check a file existence on FTP server. You need to abuse a request like GetFileSize or GetDateTimestamp.

string url = "ftp://ftp.example.com/remote/path/file.txt";

WebRequest request = WebRequest.Create(url);
request.Credentials = new NetworkCredential("username", "password");
request.Method = WebRequestMethods.Ftp.GetFileSize;
try
{
    request.GetResponse();
    Console.WriteLine("Exists");
}
catch (WebException e)
{
    FtpWebResponse response = (FtpWebResponse)e.Response;
    if (response.StatusCode == FtpStatusCode.ActionNotTakenFileUnavailable)
    {
        Console.WriteLine("Does not exist");
    }
    else
    {
        Console.WriteLine("Error: " + e.Message);
    }
}

If you want a more straightforward code, use some 3rd party FTP library.

For example with WinSCP .NET assembly, you can use its Session.FileExists method:

SessionOptions sessionOptions = new SessionOptions {
    Protocol = Protocol.Ftp,
    HostName = "ftp.example.com",
    UserName = "username",
    Password = "password",
};

Session session = new Session();
session.Open(sessionOptions);

if (session.FileExists("/remote/path/file.txt"))
{
    Console.WriteLine("Exists");
}
else
{
    Console.WriteLine("Does not exist");
}

(I'm the author of WinSCP)

Solution 4 - C#

You can use WebRequestMethods.Ftp.ListDirectory to check if a file exist, no need for nasty try catch mechanism.

    private static bool ExistFile(string remoteAddress)
    {
        int pos = remoteAddress.LastIndexOf('/');
        string dirPath = remoteAddress.Substring(0, pos); // skip the filename only get the directory

        NetworkCredential credentials = new NetworkCredential(FtpUser, FtpPass);
        FtpWebRequest listRequest = (FtpWebRequest)WebRequest.Create(dirPath);
        listRequest.Method = WebRequestMethods.Ftp.ListDirectory;
        listRequest.Credentials = credentials;
        using (FtpWebResponse listResponse = (FtpWebResponse)listRequest.GetResponse())
        using (Stream listStream = listResponse.GetResponseStream())
        using (StreamReader listReader = new StreamReader(listStream))
        {
            string fileToTest = Path.GetFileName(remoteAddress);
            while (!listReader.EndOfStream)
            {
                string fileName = listReader.ReadLine();
                fileName = Path.GetFileName(fileName);
                if (fileToTest == fileName)
                {
                    return true;
                }

            }
        }
        return false;
    }

    static void Main(string[] args)
    {
        bool existFile = ExistFile("ftp://123.456.789.12/test/config.json");
    }

Solution 5 - C#

I use FTPStatusCode.FileActionOK to check if file exists...

then, in the "else" section, return false.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTom SmykowskiView Question on Stackoverflow
Solution 1 - C#user42467View Answer on Stackoverflow
Solution 2 - C#Nolmë InformatiqueView Answer on Stackoverflow
Solution 3 - C#Martin PrikrylView Answer on Stackoverflow
Solution 4 - C#Robbert van LeeuwenView Answer on Stackoverflow
Solution 5 - C#Mikeh MiiikehView Answer on Stackoverflow