簡體   English   中英

從 FTP 服務器下載新的和修改過的文件

[英]Download new and modified files from an FTP server

我正在嘗試獲取 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 獲取信息和下載數據: 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命令。 MLSD命令以標准化的機器可讀格式提供遠程目錄列表。 命令和格式由RFC 3659標准化。

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

  • ListDirectoryDetails方法(FTP LIST命令)檢索目錄中所有文件的詳細信息,然后您處理 FTP 服務器特定格式的詳細信息(*nix 格式類似於ls *nix 命令是最常見的,缺點是格式可能會隨着時間而改變,對於較新的文件,使用“May 8 17:48”格式,而對於較舊的文件,使用“Oct 18 2009”格式)

    DOS/Windows 格式: C# 類解析 WebRequestMethods.Ftp.ListDirectoryDe​​tails FTP 響應
    *nix 格式:解析 FtpWebRequest ListDirectoryDe​​tails 行

  • GetDateTimestamp方法(一個 FTP MDTM命令)來單獨檢索每個文件的時間戳。 一個優點是響應由RFC 3659標准化為YYYYMMDDHHMMSS[.sss] 一個缺點是您必須為每個文件發送一個單獨的請求,這可能非常低效。

     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命令的 3rd 方 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 的作者)

這是FTPclient源的摘錄,它向您展示了他們如何構建自己的。 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);
    }

選項 A:我建議您使用更高級別的 FTP 客戶端庫來為您處理其中一些細節,一些可能的選項是:

選項 B:為了更直接地回答你的問題,我認為問題出在這一行:

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

似乎 FTP 服務器正在使用空格來右對齊文件名。 為了解決這個問題,我們想調整正則表達式以消耗字段之間的所有空白:

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

...其中 \\s 代表任何空白字符(通常是制表符或空格),而 + 表示它左邊的一個或多個。 這不會處理邊緣情況,例如其中包含空格的文件名。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM