C # FileSystemWatcher и FTP - PullRequest
       52

C # FileSystemWatcher и FTP

7 голосов
/ 06 августа 2009

Я отслеживаю файлы, которые сбрасываются на ftp через наблюдателя за файловой системой, затем перемещаюсь в другой каталог. Теперь я запускаю копию с события create наблюдателя файловой системы, но очевидно, что в случае с ftp создание - это просто заглушка, и данные поступают и заполняют файл по мере его загрузки до завершения. У кого-нибудь есть изящное решение для этого, или я должен делать то, что я думаю, я должен сделать

1 wait till last access time is about n ms in past before I copy
2 throw a control file in there to state that that file is done being copied, then delete control file
3 pound the crap out of it

Ответы [ 6 ]

10 голосов
/ 06 августа 2009

это очень наивная реализация, но она подходит для моих целей, я видел достаточно людей с этой проблемой в сети, поэтому решил внести свой вклад. Реализация достаточно специфична для моих потребностей. Я почти полностью не обеспокоен измененными событиями, учитывая природу моей проблемы, но люди могут добавить туда свой собственный код, если им нужно сделать что-то другое, это действительно созданный, который вызывает большинство проблем. Я не полностью проверил это, но сначала пишу, что выглядит хорошо

using System;
using System.Collections.Generic;
using System.IO;
using System.Timers;

namespace FolderSyncing
{
    public class FTPFileSystemWatcher 
    {
        private readonly string _path;
        public event FileSystemEventHandler FTPFileCreated;
        public event FileSystemEventHandler FTPFileDeleted;
        public event FileSystemEventHandler FTPFileChanged;

        private Dictionary<string, LastWriteTime> _createdFilesToCheck;
        private readonly object _lockObject = new object();
        private const int _milliSecondsSinceLastWrite = 5000;
        private const int _createdCheckTimerInterval = 2000;

        private readonly FileSystemWatcher _baseWatcher;

        public FTPFileSystemWatcher(string path, string Filter)
        {
            _path = path;
            _baseWatcher = new FileSystemWatcher(path,Filter);
            SetUpEventHandling();
        }

        public FTPFileSystemWatcher(string path)
        {
            _path = path;
            _baseWatcher = new FileSystemWatcher(path);
            SetUpEventHandling();
        }

        private void SetUpEventHandling()
        {
            _createdFilesToCheck = new Dictionary<string, LastWriteTime>();
            Timer copyTimer = new Timer(_createdCheckTimerInterval);
            copyTimer.Elapsed += copyTimer_Elapsed;
            copyTimer.Enabled = true;
            copyTimer.Start();
            _baseWatcher.EnableRaisingEvents = true;
            _baseWatcher.Created += _baseWatcher_Created;
            _baseWatcher.Deleted += _baseWatcher_Deleted;
            _baseWatcher.Changed += _baseWatcher_Changed;
        }

        void copyTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            lock (_lockObject)
            {
                Console.WriteLine("Checking : " + DateTime.Now);
                DateTime dateToCheck = DateTime.Now;
                List<string> toRemove = new List<string>();
                foreach (KeyValuePair<string, LastWriteTime> fileToCopy in _createdFilesToCheck)
                {
                    FileInfo fileToCheck = new FileInfo(_path + fileToCopy.Key);
                    TimeSpan difference = fileToCheck.LastWriteTime - fileToCopy.Value.Date;
                    fileToCopy.Value.Update(fileToCopy.Value.Date.AddMilliseconds(difference.TotalMilliseconds));
                    if (fileToCopy.Value.Date.AddMilliseconds(_milliSecondsSinceLastWrite) < dateToCheck)
                    {
                        FileSystemEventArgs args = new FileSystemEventArgs(WatcherChangeTypes.Created, _path, fileToCopy.Key);
                        toRemove.Add(fileToCopy.Key);
                        InvokeFTPFileCreated(args);
                    }
                }
                foreach (string removal in toRemove)
                {
                    _createdFilesToCheck.Remove(removal);
                }
            }
        }



        void _baseWatcher_Changed(object sender, FileSystemEventArgs e)
        {
            InvokeFTPFileChanged(e);
        }

        void _baseWatcher_Deleted(object sender, FileSystemEventArgs e)
        {
            InvokeFTPFileDeleted(e);
        }

        void _baseWatcher_Created(object sender, FileSystemEventArgs e)
        {
            if (!_createdFilesToCheck.ContainsKey(e.Name))
            {
                FileInfo fileToCopy = new FileInfo(e.FullPath);
                _createdFilesToCheck.Add(e.Name,new LastWriteTime(fileToCopy.LastWriteTime));
            }
        }

        private void InvokeFTPFileChanged(FileSystemEventArgs e)
        {
            FileSystemEventHandler Handler = FTPFileChanged;
            if (Handler != null)
            {
                Handler(this, e);
            }
        }

        private void InvokeFTPFileDeleted(FileSystemEventArgs e)
        {
            FileSystemEventHandler Handler = FTPFileDeleted;
            if (Handler != null)
            {
                Handler(this, e);
            }
        }

        private void InvokeFTPFileCreated(FileSystemEventArgs e)
        {
            FileSystemEventHandler Handler = FTPFileCreated;
            if (Handler != null)
            {
                Handler(this, e);
            }
        }
    }

    public class LastWriteTime
    {
        private DateTime _date;

        public DateTime Date
        {
            get { return _date; }
        }

        public LastWriteTime(DateTime date)
        {
            _date = date;
        }

        public void Update(DateTime dateTime)
        {
            _date = dateTime;
        }



    }
}
3 голосов
/ 06 августа 2009

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

1 голос
/ 21 марта 2015

Когда файл копируется с другого сервера с использованием FTP, перед полным копированием файла имя файла переименовывается с дополнительным расширением, например .TMP, как показано в примере пути ниже.

C: \ InterfaceServer \ OilAndGas \ XMLForTest \ TestStbFile.xml.TMP

Чтобы преодолеть эту ситуацию, выполните два шага

  1. При запуске метода наблюдателя файла FileSystemEventArgs параметр содержит имя файла с добавленным дополнительным расширением имя файла в том виде, в котором оно только что появилось в папке и не было заполнено с операцией копирования.
  2. Вам нужно просто вызвать метод ниже, чтобы удалить дополнительное расширение и добавить подождать 2 секунды в коде, чтобы полный файл создается и вы можете использовать его для дальнейшей обработки.

    public static string VerifyIfStubFile(string filePath, string extension)
    {             
        if (filePath.Length - (filePath.IndexOf(extension) + extension.Length) != 0)            
        {                
            /*LogMsg("Info : VerifyIfStubFile : Stub file found. Lets fix it!!"); */               
            return filePath = filePath.Substring(0, (filePath.IndexOf(extension) + extension.Length));            
        }            
        return filePath;        
    }
    
1 голос
/ 06 августа 2009

вот реализация для синхронизации

using System;
using System.Configuration;
using System.IO;
using System.Threading;

namespace FolderSyncing
{
    public class FolderSync
    {
        private readonly string masterDirectoryPath;
        private readonly string slaveDirectoryPath;

        public FolderSync()
        {
            masterDirectoryPath = ConfigurationManager.AppSettings.Get("MasterDirectory");
            slaveDirectoryPath = ConfigurationManager.AppSettings.Get("SlaveDirectory");

            if (Directory.Exists(masterDirectoryPath) && Directory.Exists(slaveDirectoryPath))
            {
                FTPFileSystemWatcher watcher = new FTPFileSystemWatcher(masterDirectoryPath);
                watcher.FTPFileChanged += watcher_FTPFileChanged;
                watcher.FTPFileCreated += watcher_FTPFileCreated;
                watcher.FTPFileDeleted += watcher_FTPFileDeleted;
            }
            else
            {
                Console.WriteLine("Directories were not located check config paths");
            }

        }

        void watcher_FTPFileDeleted(object sender, FileSystemEventArgs e)
        {
            DeleteFile(slaveDirectoryPath + e.Name, 5, 1);
        }

        void watcher_FTPFileCreated(object sender, FileSystemEventArgs e)
        {
            CopyFile(e.Name,5,1);
        }

        void watcher_FTPFileChanged(object sender, FileSystemEventArgs e)
        {

        }

        private void DeleteFile(string fullPath, int attempts, int attemptNo)
        {
            if (File.Exists(fullPath))
            {
                try
                {
                    File.Delete(fullPath);
                    Console.WriteLine("Deleted " + fullPath);
                }
                catch (Exception)
                {
                    if (attempts > attemptNo)
                    {
                        Console.WriteLine("Failed deleting  " + fullPath + "trying again "+ attemptNo.ToString()+ " of "+attempts);
                        Thread.Sleep(500);
                        DeleteFile(fullPath, attempts, attemptNo + 1);
                    }
                    else
                    {
                        Console.WriteLine("Critically Failed deleting  " + fullPath);
                    }
                }
            }
        }

        private void CopyFile(string fileName,int attempts, int attemptNo)
        {
            string masterFile = masterDirectoryPath + fileName;
            string slaveFile = slaveDirectoryPath + fileName;
            if (File.Exists(masterFile))
            {
                try
                {
                    File.Copy(masterFile,slaveFile);
                    Console.WriteLine("Copied  " + masterFile);
                }
                catch (Exception)
                {
                    if (attempts > attemptNo)
                    {
                        Console.WriteLine("Failed copying  " + masterFile + "trying again " + attemptNo.ToString() + " of " + attempts);
                        Thread.Sleep(500);
                        CopyFile(fileName, attempts, attemptNo + 1);
                    }
                    else
                    {
                        Console.WriteLine("Critically Failed copying  " + masterFile);
                    }
                }
            }
       }
    }
}
0 голосов
/ 24 апреля 2014

4 года спустя ....

файл-заглушка - хорошая идея, но, возможно, несколько более надежный способ сделать это - сначала создать исходный файл-заглушку, загрузить свой «настоящий» файл, а затем удалить заглушку.

0 голосов
/ 07 августа 2009

Пусть источник загрузит файл-заглушку сразу после его завершения, а ваш FileSystemWatcher будет следить за файлом-заглушкой. Например, если имя файла данных - mydata_01234, то заглушка будет mydata_01234_stub. FileSystemWatcher должен тогда иметь маску "* _stub". Затем вы узнаете имя файла данных, удалив суффикс "_stub". И заглушка не может быть загружена до тех пор, пока файл данных не будет завершен, поэтому файл данных будет свободен.

Если заглушки имеют размер всего один байт, вы сможете удалить их после любой операции, которую вы выполняете с файлом данных без проблем. Если ваши операции выполняются особенно быстро, добавьте 100 мс сна перед удалением заглушки.

...