代码之家  ›  专栏  ›  技术社区  ›  Brandon Grossutti

文件系统监视程序和ftp

  •  7
  • Brandon Grossutti  · 技术社区  · 15 年前

    我通过文件系统监视程序监视掉在FTP上的文件,然后移到另一个目录。现在,我从文件系统监视程序的create事件中触发复制,但很明显,在ftp的情况下,create只是一个存根文件,当文件上载到完成时,数据会进入并填充文件。任何人都有一个很好的解决办法,还是我必须做我认为必须做的事?

    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 回复  |  直到 15 年前
        1
  •  10
  •   Brandon Grossutti    15 年前

    这是一个非常幼稚的实现,但它符合我的目的,我在网上看到了足够多的人用这个问题做出了贡献。实现是针对我的需求的,考虑到我的问题的性质,我几乎完全不关心已更改的事件,但是如果人们需要做一些不同的事情,他们可以将自己的代码放在其中,这实际上是导致大多数问题的创建。我还没有完全测试过这个,但一开始写得不错

    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;
            }
    
    
    
        }
    }
    
        2
  •  3
  •   RichardOD    15 年前

    等到你能完全打开文件-我不会说这是一个很好的解决方案,但可能是在这种情况下最安全的策略。

        3
  •  1
  •   jp2code    8 年前

    这是一个要保持同步的实现

    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);
                        }
                    }
                }
           }
        }
    }
    
        4
  •  1
  •   Mohit S    7 年前

    当使用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;        
      }
      
        5
  •  0
  •   Richard Ambrose    15 年前

    让源文件在数据文件完成后直接上载一个存根文件,并让文件系统监视程序监视该存根文件。例如,如果数据文件名是mydata_01234,那么存根woulb就是mydata_01234_存根。然后,filesystemwatcher应该有一个“*\u stub”的掩码。然后去掉“_stub”后缀,就可以知道数据文件名。而且存根文件在数据文件完成后才能上载,所以数据文件是免费的。

    如果存根文件只有一个字节,那么在对数据文件执行任何操作之后,都应该能够删除它们,而不会产生任何问题。如果您的操作速度特别快,请在删除存根之前添加100 ms睡眠。

        6
  •  0
  •   WillyNillyMcPeep    11 年前

    4年后……

    存根文件是一个好主意,但是,一个更健壮的方法可能是让您的源文件先创建一个存根文件,上传您的“真实”文件,然后删除存根。