小编典典

将多个文件添加到目录中时,FileSystemWatcher的文件访问错误

c#

将多个文件放入监视目录时,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选项,因为我只希望一台服务器解析该文件-到达该文件的服务器首先对其进行解析。


阅读 758

收藏
2020-05-19

共1个答案

小编典典

这种方法的典型问题是在触发事件时仍在复制文件。显然,您会得到一个例外,因为文件在复制过程中被锁定。大文件特别有可能发生异常。

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

或者另一个选择是进行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将仅侦听触发器文件。

2020-05-19