从FTP服务器下载新的和修改过的文件

本文关键字:修改 文件 FTP 服务器 下载 | 更新日期: 2023-09-27 18:29:29

我正在尝试获取FTP服务器上的文件列表,然后逐一检查该文件是否存在于本地系统中,是否比较了修改日期,以及FTP文件是否更新,请下载它。

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);
    }
}

在检查文件方法中,对于每个文件(它们是.exe文件),当我分割字符串时,我会得到不同的结果,即一个文件的文件名在第18列,另一个在第16列等。我也不能总是得到文件的年份部分。

从FTP服务器下载新的和修改过的文件

首先,有一些组件可以从ftp获取信息和下载数据,可以在这里找到:http://www.limilabs.com/ftp

我写了一些从ftp获取文件名和上次修改日期的方法。

这就是我从以下行获取文件名的方法:

private string GetFtpName(string line)
{
    for (int i = 0; i < 8; i++)
        line = line.Substring(line.IndexOf(" ")).Trim();
    return line;
}

这就是我如何从ftp:获得最后一次修改日期

private DateTime GetFtpFileDate(string url, ICredentials credential)
{
    FtpWebRequest rd = (FtpWebRequest)WebRequest.Create(url);
    rd.Method = WebRequestMethods.Ftp.GetDateTimestamp;
    rd.Credentials = credential;
    FtpWebResponse response = (FtpWebResponse)rd.GetResponse();
    DateTime lmd = response.LastModified;
    response.Close();
    return lmd;
}

尝试

ListDirectory + GetDateTimestamp 

而不是

ListDirectoryDetails

为此,您需要检索远程目录列表,包括时间戳。

不幸的是,由于.NET框架不支持FTP MLSD命令,因此无法使用.NET框架提供的功能来检索时间戳。MLSD命令以标准化的机器可读格式提供远程目录列表。该命令和格式由RFC 3659标准化。

您可以使用.NET框架支持的替代方案(如其他答案所示):

  • ListDirectoryDetails方法(FTP LIST命令)检索目录中所有文件的详细信息,然后处理FTP服务器特定格式的详细信息(*nix格式类似于ls*nix命令是最常见的,缺点是格式可能会随着时间的推移而变化,对于较新的文件,使用"5月8日17:48"格式,对于较旧的文件,则使用"2009年10月18日"格式)

    DOS/Windows格式:用于解析WebRequestMethods.Ftp.ListDirectoryDetails Ftp响应的C#类
    *nix格式:解析FtpWebRequest ListDirectoryDetails行

  • CCD_ 6方法(FTP CCD_。一个优点是响应是由对YYYYMMDDHHMMSS[.sss]的RFC 3659标准化的。缺点是,您必须为每个文件发送一个单独的请求,这可能效率很低。

    const string uri = "ftp://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);
    

或者,您可以使用支持现代MLSD命令的第三方FTP客户端实现。

例如,WinSCP.NET程序集支持此功能。

您可以使用Session.ListDirectorySession.EnumerateRemoteFiles方法读取返回集合中文件的RemoteFileInfo.LastWriteTime

或者更简单的是,您可以使用Session.SynchronizeDirectories让库自动下载(同步)修改后的文件:

// Setup session options
SessionOptions sessionOptions = new SessionOptions
{
    Protocol = Protocol.Ftp,
    HostName = "ftp.example.com",
    UserName = "user",
    Password = "mypassword",
};
using (Session session = new Session())
{
    // Connect
    session.Open(sessionOptions);
    // Synchronize files
    session.SynchronizeDirectories(
        SynchronizationMode.Local, @"d:'www", "/remote/path", false).Check();
}

(我是WinSCP的作者)

选项A:我建议您使用更高级别的FTP客户端库来处理其中的一些细节,一些可能的选项是:

  • http://ftplib.codeplex.com/
  • http://ftps.codeplex.com/
  • http://netftp.codeplex.com/

选项B:为了更直接地回答你的问题,我认为问题出在这条线上:

string[] splitDownloadFile = Regex.Split(dFile, " ");

FTP服务器似乎在使用空格来右对齐文件名。为了解决这个问题,我们需要调整正则表达式以消耗字段之间的所有空白:

string[] splitDownloadFile = Regex.Split(dFile, "'s+");

其中,''s代表任何空白字符(通常是制表符或空格),+表示它左边的一个或多个字符。这将不处理边缘大小写,例如带有空格的文件名。

这里有一个FTPclient源代码的exept,它向您展示了他们是如何构建自己的。FtpFileInfo对象。我无法对此进行测试,以确保目前这在所有情况下都能工作,但也许它会给你一些想法。

    /// <summary>
    /// Return a detailed directory listing, and also download datetime stamps if specified
    /// </summary>
    /// <param name="directory">Directory to list, e.g. /pub/etc</param>
    /// <param name="doDateTimeStamp">Boolean: set to True to download the datetime stamp for files</param>
    /// <returns>An FTPDirectory object</returns>
    public FTPdirectory ListDirectoryDetail(string directory, bool doDateTimeStamp)
    {
        System.Net.FtpWebRequest ftp = GetRequest(GetDirectory(directory));
        // Set request to do simple list
        ftp.Method = System.Net.WebRequestMethods.Ftp.ListDirectoryDetails;
        string str = GetStringResponse(ftp);
        // replace CRLF to CR, remove last instance
        str = str.Replace("'r'n", "'r").TrimEnd(''r');
        // split the string into a list
        FTPdirectory dir = new FTPdirectory(str, _lastDirectory);
        // download timestamps if requested
        if (doDateTimeStamp)
        {
            foreach (FTPfileInfo fi in dir)
            {
                fi.FileDateTime = this.GetDateTimestamp(fi);
            }
        }
        return dir;
    }
    /// <summary>
    /// Obtain datetimestamp for remote file
    /// </summary>
    /// <param name="filename"></param>
    /// <returns></returns>
    public DateTime GetDateTimestamp(string filename)
    {
        string path;
        if (filename.Contains("/"))
        {
            path = AdjustDir(filename);
        }
        else
        {
            path = this.CurrentDirectory + filename;
        }
        string URI = this.Hostname + path;
        FtpWebRequest ftp = GetRequest(URI);
        ftp.Method = WebRequestMethods.Ftp.GetDateTimestamp;
        return this.GetLastModified(ftp);
    }