c# - 将多个文件添加到目录时,FileSystemWatcher 出现文件访问错误

标签 c# exception-handling filesystemwatcher file-access

当将多个文件放入监视目录时,我遇到了 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: The process cannot access the file 'C:\Temp\TestFile.txt' because it is being used by another process.

如果它在多台机器上运行,我希望看到这个错误,但它现在只在一台服务器上运行。不应有其他进程使用此文件 - 我已创建它们并将它们复制到应用程序运行时的目录中。

这是设置 FileSystemWatcher 的正确方法吗?我怎样才能看到什么锁定了这个文件?为什么它不解析这两个文件——我必须关闭 FileStream 吗?我想保留 FileShare.None 选项,因为我只希望一台服务器解析文件 - 获取文件的服务器首先解析它。

最佳答案

这种方法的一个典型问题是当事件被触发时文件仍在被复制。显然,你会得到一个异常,因为文件在复制过程中被锁定了。大文件特别容易出现异常。

作为解决方法,您可以先复制文件,然后重命名并监听重命名事件。

或者另一种选择是让一个 while 循环检查文件是否可以用写访问权限打开。如果可以,您将知道复制已完成。 C# 代码可能如下所示(在生产系统中,您可能希望有最大重试次数或超时次数,而不是 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 只会监听触发器文件。

关于c# - 将多个文件添加到目录时,FileSystemWatcher 出现文件访问错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/699538/

相关文章:

c# - 用字符串拆分字符串时出错

jsf - 使用 JSF 生成 HTTP 错误代码页面以及异常错误页面?

.net - System.IO.FileSystemWatcher 监视网络服务器文件夹 - 性能注意事项

c# - FileSystemWatcher 无法访问文件,因为已在其他进程中使用

c# - 区分同名的 Windows 服务?

c# - 将控制台输出写入文件

java - JNI Uncaught exception of type <unknown> ...这是怎么发生的?

java - 为什么扫描仪不在 try-catch while 循环 java 中要求其他输入

c# - WPF DependencyObject 调用线程异常

c# - 将 Button 的可见性绑定(bind)到 ViewModel 中的 bool 值