2

I need to download files from specific folder on FTP, but only the ones with creation time within last hour. So basically I need to list all files from that folder, and then download only the ones for which time stamp doesn't differ for more then one hour from execution time. Any ideas on how to parse Time Stamp for file on FTP? I can not use any 3rd-party FTP client libraries.

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992

3 Answers3

2

This is what I came up with for now. Sure there is some more elegant way to handle this but...

foreach (var fileName in filesNamesFromFtpFolder)
        {
            FtpWebRequest request = (FtpWebRequest)FtpWebRequest.Create(@"ftp://" + host + @"/" + folder + @"/" + fileName);

            request.Method = WebRequestMethods.Ftp.GetDateTimestamp;
            request.Proxy = null;

            using (FtpWebResponse resp = (FtpWebResponse)request.GetResponse())
            {
                if (DateTime.Now.Subtract(TimeSpan.FromMinutes(60)) < resp.LastModified)
                {
                    //download this file...
                }
            }
        }
2

Unfortunately, there's no really reliable and efficient way to retrieve modification timestamp of all files in a directory using features offered by .NET framework, as it does not support the FTP MLSD. The MLSD command provides a listing of remote directory in a standardized machine-readable format. The command and the format is standardized by RFC 3659.

Alternatives you can use, that are supported by .NET framework:

  • ListDirectoryDetails method (the FTP LIST command) to retrieve details of all files in a directory and then you deal with FTP server specific format of the details

    DOS/Windows format: C# class to parse WebRequestMethods.Ftp.ListDirectoryDetails FTP response
    *nix format: Parsing FtpWebRequest ListDirectoryDetails line

  • GetDateTimestamp method (the FTP MDTM command) to individually retrieve timestamps for each file. An advantage is that the response is standardized by RFC 3659 to YYYYMMDDHHMMSS[.sss]. A disadvantage is that you have to send a separate request for each file, what can be quite inefficient. The file modification time is parsed for you into LastModified property:

    const string uri = "ftp://example.com/remote/path/file.txt";
    FtpWebRequest request = (FtpWebRequest)WebRequest.Create(uri);
    request.Method = WebRequestMethods.Ftp.GetDateTimestamp;
    FtpWebResponse response = (FtpWebResponse)request.GetResponse();
    Console.WriteLine("{0} {1}", uri, response.LastModified);
    if (response.LastModified > DateTime.Now.Subtract(TimeSpan.FromHours(1)))
    {
        // download
    }
    

Way easier is to use (I know you cannot) a 3rd party FTP client implementation that supports the modern MLSD command or that can directly download files given a time constraint.

For example WinSCP .NET assembly supports both MLSD and time constraints.

There's even an example for your specific task: How do I transfer new/modified files only?
The example is for PowerShell, but translates to C# easily:

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

using (Session session = new Session())
{
    // Connect
    session.Open(sessionOptions);

    // Download files modified with the last hour
    TransferOptions transferOptions = new TransferOptions();
    transferOptions.FileMask = "*>=1H";
    session.GetFiles(
        "/remote/path/*", @"C:\local\path\", false, transferOptions).Check();
}

See also syntax for time constraints.

(I'm the author of WinSCP)

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
1

The main task can possibly be not the reading file timestamp, but in determining it's modified within one last hour. If you server located in the same TimeZone, then it will be same as your time. If not, there will be some time shift. If you are using same server all the time, this can be fixed in rather reliable fashion. But if you are using multiple servers all over the world then this becomes a little more complicated. So be aware.

Petr Abdulin
  • 33,883
  • 9
  • 62
  • 96