如何确定文件夹是否已完成复制c#

我有一个问题:如何确定文件夹是否已从一个位置复制到另一个位置?

目前,我的FileSystemWatcher会在复制目录中的文件后立即触发多个事件。 我想要的是,当成功复制该文件夹中的所有文件时,将触发一个单一事件。 我的代码现在看起来像这样:

static void Main(string[] args) { String path = @"D:\Music"; FileSystemWatcher mWatcher = new FileSystemWatcher(); mWatcher.Path = path; mWatcher.NotifyFilter = NotifyFilters.LastAccess; mWatcher.NotifyFilter = mWatcher.NotifyFilter | NotifyFilters.LastWrite; mWatcher.NotifyFilter = mWatcher.NotifyFilter | NotifyFilters.DirectoryName; mWatcher.IncludeSubdirectories = true; mWatcher.Created += new FileSystemEventHandler(mLastChange); mWatcher.Changed += new FileSystemEventHandler(mLastChange); mWatcher.EnableRaisingEvents = true; Console.WriteLine("Watching path: " + path); String exit; while (true) { exit = Console.ReadLine(); if (exit == "exit") break; } } private static void mLastChange(Object sender, FileSystemEventArgs e) { Console.WriteLine(e.ChangeType + " " + e.FullPath); } 

不幸的是,FileSystemWatcher没有告诉你文件写完的时间。 所以你的选择是……

  1. 在假设没有更多更改到来时,在上次写入后设置超时
  2. 让编写应用程序放置一个多种类型的锁定文件,告诉任何其他程序它已完成。

在重新阅读您的问题之后……听起来您对其他应用程序没有任何控制权。

因此,您需要某种超时值来确定何时完成所有写入操作。 基本上创建一个计时器,在每个filesystemwatcher事件之后重置…当它超时时,你会触发表明它完成的单个事件。

以下是如何将其添加到您的代码中…

 static void Main(string[] args) { Timer.Interval = 5000; // 5 seconds - change to whatever is appropriate Timer.AutoReset = false; Timer.Elapsed += TimeoutDone; String path = @"D:\Music"; FileSystemWatcher mWatcher = new FileSystemWatcher(); mWatcher.Path = path; mWatcher.NotifyFilter = NotifyFilters.LastAccess; mWatcher.NotifyFilter = mWatcher.NotifyFilter | NotifyFilters.LastWrite; mWatcher.NotifyFilter = mWatcher.NotifyFilter | NotifyFilters.DirectoryName; mWatcher.IncludeSubdirectories = true; mWatcher.Created += new FileSystemEventHandler(mLastChange); mWatcher.Changed += new FileSystemEventHandler(mLastChange); mWatcher.EnableRaisingEvents = true; Console.WriteLine("Watching path: " + path); Timer.Start(); String exit; while (true) { exit = Console.ReadLine(); if (exit == "exit") break; } } private static Timer Timer = new Timer(); private static void TimeoutDone(object source, ElapsedEventArgs e) { Console.WriteLine("Timer elapsed!"); } private static void mLastChange(Object sender, FileSystemEventArgs e) { Console.WriteLine(e.ChangeType + " " + e.FullPath); if (Timer != null) { Timer.Stop(); Timer.Start(); } } 

它非常俗气,但在过去我通过为FileSystemWatcher类创建自定义装饰器来处理这个问题。 在内部,它创建一个FileSystemWatcher并注册Created和Changed事件,包装它们,并在文件完成后抛出自己的Created和Changed事件,类似于:

 private void Watcher_Changed(Object sender, FileSystemEVentArgs e) { while (true) { FileStream stream; try { stream = File.Open(e.FullPath, FileMode.Open, FileAccess.ReadWrite, FileShare.None); // If this succeeds, the file is finished Changed(); } catch (IOException) { } finally { if (stream != null) stream.Close(); } } } 

其中一些来自这里的答案。 实际上,您不应该使用无限循环。 你可能想要增加超时,在支票之间睡觉等等,但这是一般的想法。

如果目标是本地文件夹,则可以使用文件系统筛选器驱动程序来跟踪文件创建文件关闭事件。 知道以前创建的所有文件何时关闭将通知您复制完成。

我创建了一个Git仓库,其中包含一个扩展FileSystemWatcher的类,仅在复制完成时触发事件。

下载FileSystemSafeWatcher并将其添加到您的项目中。

然后将其用作普通的FileSystemWatcher并监视触发事件的时间。

 var fsw = new FileExamSystemWatcher(file); fsw.EnableRaisingEvents = true; // Add event handlers here fsw.Created += fsw_Created;