I'm trying to get a list of the files on an FTP server, then one by one check if that file exists on the local system and if it does compare the dates modified and if the ftp file is newer download it.
private void btnGo_Click(object sender, EventArgs e)
{
string[] files = GetFileList();
foreach (string file in files)
{
if (file.Length >= 5)
{
string uri = "ftp://" + ftpServerIP + "/" + remoteDirectory + "/" + file;
Uri serverUri = new Uri(uri);
CheckFile(file);
}
}
this.Close();
}
public string[] GetFileList()
{
string[] downloadFiles;
StringBuilder result = new StringBuilder();
WebResponse response = null;
StreamReader reader = null;
try
{
FtpWebRequest reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://" + ftpServerIP + "/" + remoteDirectory));
reqFTP.UseBinary = true;
reqFTP.Credentials = new NetworkCredential(ftpUserID, ftpPassword);
reqFTP.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
reqFTP.Proxy = null;
reqFTP.KeepAlive = false;
reqFTP.UsePassive = false;
response = reqFTP.GetResponse();
reader = new StreamReader(response.GetResponseStream());
string line = reader.ReadLine();
while (line != null)
{
result.Append(line);
result.Append("\n");
line = reader.ReadLine();
}
result.Remove(result.ToString().LastIndexOf('\n'), 1);
return result.ToString().Split('\n');
}
catch
{
if (reader != null)
{
reader.Close();
}
if (response != null)
{
response.Close();
}
downloadFiles = null;
return downloadFiles;
}
}
private void CheckFile(string file)
{
string dFile = file;
string[] splitDownloadFile = Regex.Split(dFile, " ");
string fSize = splitDownloadFile[13];
string fMonth = splitDownloadFile[14];
string fDate = splitDownloadFile[15];
string fTime = splitDownloadFile[16];
string fName = splitDownloadFile[17];
string dateModified = fDate + "/" + fMonth+ "/" + fYear;
DateTime lastModifiedDF = Convert.ToDateTime(dateModified);
string[] filePaths = Directory.GetFiles(localDirectory);
// if there is a file in filePaths that is the same as on the server compare them and then download if file on server is newer
foreach (string ff in filePaths)
{
string[] splitFile = Regex.Split(ff, @"\\");
string fileName = splitFile[2];
FileInfo fouFile = new FileInfo(ff);
DateTime lastChangedFF = fouFile.LastAccessTime;
if (lastModifiedDF > lastChangedFF) Download(fileName);
}
}
In the check file method, for each file (they are .exe files) I keep getting different results when I split the string i.e. for one file the file name was at column 18 another it was at 16 etc. I also can't always get the year portion of the file.
Option A: I'd recommend that you use a higher-level FTP client library that handles some of these details for you, a few likely options are:
Option B: To answer your question more directly, I think the issue is with this line:
It seems like the FTP server is using spaces to right-align the filenames. To deal with that, we want to adjust the regex to consume all whitespace between the fields:
...where \s stands for any whitespace character (usually tabs or spaces), and + means one or more of the thing to the left of it. This will not handle edge cases, such as file names with spaces in them.
First of all, there are some components for which you can get info and download data from ftp can be found here: http://www.limilabs.com/ftp
I wrote some methods for get filename and last modified date from ftp.
This is how I get the filename from line:
And this is how I get the last modified date from ftp:
Here is an exerpt from the FTPclient source which shows you how they are building their. FtpFileInfo objects. I'm not able to test to this make sure this will work in all cases at the moment, but maybe it will give you some ideas.
For this, you need to retrieve a remote directory listing, including timestamps.
Unfortunately, there's no really reliable and efficient way to retrieve timestamps using features offered by the .NET framework as it does not support the FTP
MLSD
command. TheMLSD
command provides listing of remote directory in a standardized machine-readable format. The command and the format is standardized by the RFC 3659.Alternatives you can use, that are supported by the .NET framework (as the other answers show):
the
ListDirectoryDetails
method (the FTPLIST
command) to retrieve details of all files in a directory and then you deal with FTP server specific format of the details (*nix format similar tols
*nix command is the most common, drawback is that the format may change over time, as for newer files "May 8 17:48" format is used and for older files "Oct 18 2009" format is used)DOS/Windows format: C# class to parse WebRequestMethods.Ftp.ListDirectoryDetails FTP response
*nix format: Parsing FtpWebRequest ListDirectoryDetails line
the
GetDateTimestamp
method (an FTPMDTM
command) to individually retrieve timestamps for each file. An advantage is that the response is standardized by the RFC 3659 toYYYYMMDDHHMMSS[.sss]
. A disadvantage is that you have to send a separate request for each file, what can be quite inefficient.Alternatively you can use a 3rd party FTP client implementation that supports the modern
MLSD
command.For example the WinSCP .NET assembly supports that.
You can use the
Session.ListDirectory
or theSession.EnumerateRemoteFiles
methods and read theRemoteFileInfo.LastWriteTime
of the files in returned collection.Or even easier, you can use the
Session.SynchronizeDirectories
to have the library automatically download (synchronize) the modified files:(I'm the author of WinSCP)
Try
instead of