سؤال

كيف يمكنني تنفيذ FileSystemWatcher لموقع FTP (في C #). هذه الفكرة هي كلما تمت إضافة أي شيء في موقع FTP، أود نسخه إلى جهازي المحلي. أي أفكار سوف تكون مفيدة.

هذه متابعة سؤالي السابق تنزيل FTP الانتقائي باستخدام .NET.

هل كانت مفيدة؟

المحلول

سيتعين عليك تنفيذ حل الاقتراع، حيث تستمر في مطالبة محتوى الدليل بشكل دوري. قارن هذا إلى قائمة مخزنة مؤقتا من المكالمة السابقة وتحديد ما حدث بهذه الطريقة.

لا يوجد شيء في بروتوكول FTP الذي سيساعدك في هذا الأمر للأسف.

نصائح أخرى

ال FileSystemWatcher تعمل الطبقة عن طريق التسجيل للحصول على الأحداث باستخدام نظام التشغيل Windows المضيف. على هذا النحو، يقتصر على العمل على المسارات المحلية ومسارات UNC إلى الدلائل المستضافة على أنظمة Windows. وثائق MSDN على FileSystemWatcher يشرح المسارات التي يمكنك استخدامها وبعض المشاكل المحتملة باستخدام الفصل.

إذا كنت تتطلع إلى التنبيه للتغييرات على موقع FTP، فسيتعين عليك استخدام آلية الاقتراع لطلب الحالة الحالية للملفات أو المجلدات التي تهتم بها المراقبة. ستتمكن من معرفة متى يتم إضافة الملفات وإزالتها عن طريق مقارنة اللقطات لموقع FTP للتغييرات وترفع أحداث مماثلة عند اكتشاف التغييرات. لسوء الحظ، لن تكون قادرا على اكتشاف أحداث إعادة تسمية، ولكن يجب أن تكون التغييرات الأخرى سهلة مراقبة هذه الطريقة.

لا يمكنك استخدام FileSystemWatcher أو بأي طريقة أخرى، لأن بروتوكول FTP لا يحتوي على أي API لإعلام عميل حول التغييرات في الدليل البعيد.

كل ما يمكنك فعله هو تكرار الشجرة البعيدة بشكل دوري وإيجاد التغييرات.

إنه في الواقع سهلة التنفيذ، إذا كنت تستخدم مكتبة عميل FTP تدعم قائمة العودية لشجرة عن بعد. لسوء الحظ، عميل FTP المدمج في .NET، FtpWebRequest لا. ولكن على سبيل المثال مع WINSCP .NET التجمع الإصدار 5.9 (أو الأحدث)، يمكنك استخدام Session.EnumerateRemoteFiles طريقة.

انظر المادة مشاهدة التغييرات في خادم SFTP / FTP:

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

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

    List<string> prevFiles = null;

    while (true)
    {
        // Collect file list
        List<string> files =
            session.EnumerateRemoteFiles(
                "/remote/path", "*.*", EnumerationOptions.AllDirectories)
            .Select(fileInfo => fileInfo.FullName)
            .ToList();
        if (prevFiles == null)
        {
            // In the first round, just print number of files found
            Console.WriteLine("Found {0} files", files.Count);
        }
        else
        {
            // Then look for differences against the previous list
            IEnumerable<string> added = files.Except(prevFiles);
            if (added.Any())
            {
                Console.WriteLine("Added files:");
                foreach (string path in added)
                {
                    Console.WriteLine(path);
                }
            }

            IEnumerable<string> removed = prevFiles.Except(files);
            if (removed.Any())
            {
                Console.WriteLine("Removed files:");
                foreach (string path in removed)
                {
                    Console.WriteLine(path);
                }
            }
        }

        prevFiles = files;

        Console.WriteLine("Sleeping 10s...");
        Thread.Sleep(10000);
    }
}

(أنا مؤلف WinSCP)


رغم ذلك، إذا كنت ترغب بالفعل في تنزيل التغييرات، فهي طريقة أسهل. مجرد استخدام Session.SynchronizeDirectories في الحلقة.

session.SynchronizeDirectories(
    SynchronizationMode.Local, "/remote/path", @"C:\local\path", true).Check();

إذا كنت لا ترغب في استخدام مكتبة الطرف الثالث، عليك أن تفعل مع حدود FtpWebRequest. وبعد مثال على سبيل المثال، سرد شجرة دليل بعيد مع FtpWebRequest, ، انظر جوابي C # قم بتنزيل جميع الملفات والدلائل الفرعية من خلال FTP.

اكتب خدمة بسيطة لإنشاء FileSystemWatcher، مشيرا إلى موقع FTP الخاص بك.

ثم عند تحميل ملف أو تعديله، سيتم إطلاق حدث حدث في خدمتكم، والذي يمكنك استخدامه بعد ذلك لنسخ الملف إلى جهازك المحلي.
file.copy الخ

إلقاء نظرة على: هذه بلوق

يمكنك مراقبة موقع FTP بالطريقة التالية:

public class FtpFileSystemWatcher
{

    public bool IsRunning
    {
        get;
        private set;
    }
    public string FtpUserName
    {
        get;
        set;
    }
    public string FtpPassword
    {
        get;
        set;
    }
    public string FtpLocationToWatch
    {
        get;
        set;
    }
    public string DownloadTo
    {
        get;
        set;
    }
    public bool KeepOrignal
    {
        get;
        set;
    }
    public bool OverwriteExisting
    {
        get;
        set;
    }
    public int RecheckIntervalInSeconds
    {
        get;
        set;
    }
    private bool DownloadInprogress
    {
        get;
        set;
    }

    private System.Timers.Timer JobProcessor;

    public FtpFileSystemWatcher(string FtpLocationToWatch = "", string DownloadTo = "", int RecheckIntervalInSeconds = 1, string UserName = "", string Password = "", bool KeepOrignal = false, bool OverwriteExisting = false)
    {
        this.FtpUserName = UserName;
        this.FtpPassword = Password;
        this.FtpLocationToWatch = FtpLocationToWatch;
        this.DownloadTo = DownloadTo;
        this.KeepOrignal = KeepOrignal;
        this.RecheckIntervalInSeconds = RecheckIntervalInSeconds;
        this.OverwriteExisting = OverwriteExisting;

        if (this.RecheckIntervalInSeconds < 1) this.RecheckIntervalInSeconds = 1;
    }

    public void StartDownloading()
    {

        JobProcessor = new Timer(this.RecheckIntervalInSeconds * 1000);
        JobProcessor.AutoReset = false;
        JobProcessor.Enabled = false;
        JobProcessor.Elapsed += (sender, e) =>
        {
            try
            {

                this.IsRunning = true;

                string[] FilesList = GetFilesList(this.FtpLocationToWatch, this.FtpUserName, this.FtpPassword);

                if (FilesList == null || FilesList.Length < 1)
                {
                    return;
                }

                foreach (string FileName in FilesList)
                {
                    if (!string.IsNullOrWhiteSpace(FileName))
                    {
                        DownloadFile(this.FtpLocationToWatch, this.DownloadTo, FileName.Trim(), this.FtpUserName, this.FtpPassword, this.OverwriteExisting);

                        if (!this.KeepOrignal)
                        {
                            DeleteFile(Path.Combine(this.FtpLocationToWatch, FileName.Trim()), this.FtpUserName, this.FtpPassword);
                        }
                    }
                }

                this.IsRunning = false;
                JobProcessor.Enabled = true;                    
            }

            catch (Exception exp)
            {
                this.IsRunning = false;
                JobProcessor.Enabled = true;
                Console.WriteLine(exp.Message);
            }
        };

        JobProcessor.Start();
    }

    public void StopDownloading()
    {
        try
        {
            this.JobProcessor.Dispose();
            this.IsRunning = false;
        }
        catch { }
    }

    private void DeleteFile(string FtpFilePath, string UserName, string Password)
    {
        FtpWebRequest FtpRequest;
        FtpRequest = (FtpWebRequest)FtpWebRequest.Create(new Uri(FtpFilePath));
        FtpRequest.UseBinary = true;
        FtpRequest.Method = WebRequestMethods.Ftp.DeleteFile;

        FtpRequest.Credentials = new NetworkCredential(UserName, Password);
        FtpWebResponse response = (FtpWebResponse)FtpRequest.GetResponse();
        response.Close();

    }
    private void DownloadFile(string FtpLocation, string FileSystemLocation, string FileName, string UserName, string Password, bool OverwriteExisting)
    {
        try
        {
            const int BufferSize = 2048;
            byte[] Buffer = new byte[BufferSize];

            FtpWebRequest Request;
            FtpWebResponse Response;

            if (File.Exists(Path.Combine(FileSystemLocation, FileName)))
            {
                if (OverwriteExisting)
                {
                    File.Delete(Path.Combine(FileSystemLocation, FileName));
                }
                else
                {
                    Console.WriteLine(string.Format("File {0} already exist.", FileName));
                    return;
                }
            }

            Request = (FtpWebRequest)FtpWebRequest.Create(new Uri(Path.Combine(FtpLocation, FileName)));
            Request.Credentials = new NetworkCredential(UserName, Password);
            Request.Proxy = null;
            Request.Method = WebRequestMethods.Ftp.DownloadFile;
            Request.UseBinary = true;

            Response = (FtpWebResponse)Request.GetResponse();

            using (Stream s = Response.GetResponseStream())
            {
                using (FileStream fs = new FileStream(Path.Combine(FileSystemLocation, FileName), FileMode.CreateNew, FileAccess.ReadWrite))
                {
                    while (s.Read(Buffer, 0, BufferSize) != -1)
                    {
                        fs.Write(Buffer, 0, BufferSize);
                    }
                }
            }
        }
        catch { }

    }
    private string[] GetFilesList(string FtpFolderPath, string UserName, string Password)
    {
        try
        {
            FtpWebRequest Request;
            FtpWebResponse Response;

            Request = (FtpWebRequest)FtpWebRequest.Create(new Uri(FtpFolderPath));
            Request.Credentials = new NetworkCredential(UserName, Password);
            Request.Proxy = null;
            Request.Method = WebRequestMethods.Ftp.ListDirectory;
            Request.UseBinary = true;

            Response = (FtpWebResponse)Request.GetResponse();
            StreamReader reader = new StreamReader(Response.GetResponseStream());
            string Data = reader.ReadToEnd();

            return Data.Split('\n');
        }
        catch
        {
            return null;
        }
    }


}

الطريقة التي تتعامل معها هي تحميل صفيف بايت عنصر واحد، باسم ".ftpcomplete". يشاهد FileSystemWatcher فقط ل ".ftpcomplete" الملفات، وشرائط من النهاية لمعرفة الملف الفعلي الذي تم تحميله. نظرا لأن الملف ".ftpcomplete" هو فقط 1 بايت، فهو يرتفع بأسرع وقت يتم إنشاؤه على خادم FTP، لذلك يمكن حذفه بمجرد القيام بكل ما تحتاج إليه مع الملف الذي تم الرصاص به الرئيسي

        FtpWebRequest request = (FtpWebRequest)FtpWebRequest.Create(
            FTPAddress + "/" + Path.GetFileName(filePath) + ".ftpComplete");
        request.Method = WebRequestMethods.Ftp.UploadFile;
        request.Credentials = new NetworkCredential(username, password);
        request.UsePassive = true;
        request.UseBinary = true;
        request.KeepAlive = false;
        byte[] buffer = new byte[1];
        Stream reqStream = request.GetRequestStream();
        reqStream.Write(buffer, 0, buffer.Length);
        reqStream.Close();

يمكنك استخدام برنامج نصي روبو بروتوكول نقل الملفات لمراقبة موقع FTP للتغييرات. هنا رابط إلى Script عينة يرسل رسالة بريد إلكتروني كلما تم اكتشاف تغيير: http://kb.robo-ftp.com/script_library/show/40.

نظرت إلى السؤال السابق الذي ربطته. أعتقد أنه يجب أن تكون قادرا على تعديل عينة Robo-FTP واستخدام واهن قم بأمر مع خيار / تقسيم لجعله تحليل اسم المجلد ورقم ملف ISO من الملف الذي تم تغييره ثم نقل الملف إلى الموقع المناسب.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top