Загрузка новых и измененных файлов с FTP-сервера - PullRequest
2 голосов
/ 30 марта 2012

Я пытаюсь получить список файлов на 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 и т. Д. Я также не всегда могу получить часть файла за год.

Ответы [ 5 ]

2 голосов
/ 30 марта 2012

Прежде всего, есть некоторые компоненты, для которых вы можете получить информацию и загрузить данные с 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;
}
1 голос
/ 01 августа 2017

Для этого вам нужно получить список удаленных каталогов, включая временные метки.

К сожалению, нет действительно надежного и эффективного способа получения меток времени с использованием функций, предлагаемых .NET Framework, поскольку он не поддерживает команду FTP MLSD. Команда MLSD предоставляет список удаленных каталогов в стандартизированном машиночитаемом формате. Команда и формат стандартизированы RFC 3659 .

Альтернативы, которые вы можете использовать, которые поддерживаются платформой .NET (как показывают другие ответы):

  • метод ListDirectoryDetails (команда FTP LIST) для получения сведений обо всех файлах в каталоге, а затем вы работаете с конкретным форматом данных сервера FTP (формат * nix) похож на ls * nix команда является самой распространенной, недостатком является то, что формат может меняться со временем, так как для более новых файлов используется формат «8 мая 17:48», а для более старых файлов используется формат «18 октября 2009»)

    Формат DOS / Windows: Класс C # для анализа WebRequestMethods.Ftp.ListDirectoryDetails FTP-ответ
    * nix формат: Синтаксический анализ строки списка FtpWebRequestDirectoryDetails

  • метод 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);
    

В качестве альтернативы вы можете использовать стороннюю реализацию FTP-клиента, которая поддерживает современную команду MLSD.

Например, сборка WinSCP .NET поддерживает это.

Вы можете использовать методы Session.ListDirectory или Session.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)

1 голос
/ 20 апреля 2012

Попробуйте

ListDirectory + GetDateTimestamp 

вместо

ListDirectoryDetails
0 голосов
/ 30 марта 2012

Вариант A: Я бы порекомендовал вам использовать высокоуровневую клиентскую библиотеку FTP, которая обрабатывает некоторые из этих деталей для вас, несколько вероятных вариантов:

Вариант B: Чтобы ответить на ваш вопрос более прямо, я думаю, что проблема в этой строке:

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

Похоже, FTP-сервер использует пробелы для выравнивания имен файлов по правому краю. Чтобы справиться с этим, мы хотим настроить регулярное выражение так, чтобы оно занимало все пробелы между полями:

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

... где \ s обозначает любой символ пробела (обычно табуляция или пробел), а + означает одну или несколько вещей слева от него. Это не будет обрабатывать крайние случаи, такие как имена файлов с пробелами в них.

0 голосов
/ 30 марта 2012

Вот отрывок из источника 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);
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...