将多个文件放入监视目录时,FileSystemWatcher出现问题。我想在将文件放入目录后立即对其进行解析。通常,第一个文件可以很好地解析,但是将第二个文件添加到目录中会导致访问问题。有时,第一个文件甚至不会解析。只有一个应用程序正在运行并监视此目录。最终,此过程将在多台计算机上运行,并且它们将监视共享目录,但是当将数据导入数据库时,只有一台服务器可以解析每个文件,并且没有主键。
这是FileSystemWatcher代码:
public void Run() { FileSystemWatcher watcher = new FileSystemWatcher("C:\\temp"); watcher.NotifyFilter = NotifyFilters.FileName; watcher.Filter = "*.txt"; watcher.Created += new FileSystemEventHandler(OnChanged); watcher.EnableRaisingEvents = true; System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite); }
然后解析文件的方法:
private void OnChanged(object source, FileSystemEventArgs e) { string line = null; try { using (FileStream fs = new FileStream(e.FullPath, FileMode.Open, FileAccess.Read, FileShare.None)) { using (StreamReader sr = new StreamReader(fs)) { while (sr.EndOfStream == false) { line = sr.ReadLine(); //parse the line and insert into the database } } } } catch (IOException ioe) { Console.WriteLine("OnChanged: Caught Exception reading file [{0}]", ioe.ToString()); }
移动第二个文件时,它正在捕获
System.IO.IOException:该进程无法访问文件’C:\ Temp \ TestFile.txt’,因为它正在被另一个进程使用。
如果它在多台计算机上运行,我希望看到此错误,但是目前仅在一台服务器上运行。使用该文件不应再有其他进程- 我创建了它们,并在应用程序运行时将它们复制到目录中。
这是设置FileSystemWatcher的正确方法吗?如何查看此文件的锁?为什么不解析两个文件- 我必须关闭FileStream吗?我想保留FileShare.None选项,因为我只希望一台服务器解析该文件-到达该文件的服务器首先对其进行解析。
这种方法的典型问题是在触发事件时仍在复制文件。显然,您会得到一个例外,因为文件在复制过程中被锁定。大文件特别有可能发生异常。
解决方法是,您可以先复制文件,然后重命名文件并侦听重命名事件。
或者另一个选择是进行while循环,以检查是否可以使用写访问权限打开文件。如果可以,您将知道复制已完成。C#代码可能看起来像这样(在生产系统中,您可能希望具有最大的重试次数或超时次数,而不是while(true)):
while(true)
/// <summary> /// Waits until a file can be opened with write permission /// </summary> public static void WaitReady(string fileName) { while (true) { try { using (Stream stream = System.IO.File.Open(fileName, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)) { if (stream != null) { System.Diagnostics.Trace.WriteLine(string.Format("Output file {0} ready.", fileName)); break; } } } catch (FileNotFoundException ex) { System.Diagnostics.Trace.WriteLine(string.Format("Output file {0} not yet ready ({1})", fileName, ex.Message)); } catch (IOException ex) { System.Diagnostics.Trace.WriteLine(string.Format("Output file {0} not yet ready ({1})", fileName, ex.Message)); } catch (UnauthorizedAccessException ex) { System.Diagnostics.Trace.WriteLine(string.Format("Output file {0} not yet ready ({1})", fileName, ex.Message)); } Thread.Sleep(500); } }
另一种方法是在复制完成后在文件夹中放置一个小的触发器文件。您的FileSystemWatcher将仅侦听触发器文件。