将多个文件添加到目录时,FileSystemWatcher 出现文件访问错误 [英] File access error with FileSystemWatcher when multiple files are added to a directory

查看:31
本文介绍了将多个文件添加到目录时,FileSystemWatcher 出现文件访问错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当多个文件被放入监视目录时,我遇到了 FileSystemWatcher 的问题.我想在将文件放入目录后立即对其进行解析.通常,第一个文件解析良好,但将第二个文件添加到目录会导致访问问题.有时,第一个文件甚至不解析.只有一个应用程序正在运行并监视此目录.最终,这个进程将在多台机器上运行,他们将监视一个共享目录,但只有一个服务器可以解析每个文件,因为数据被导入到数据库中,并且没有主键.

I am running into an issue with a FileSystemWatcher when multiple files are placed into the watched directory. I want to parse the file as soon as it is placed in the directory. Typically, the first file parses fine, but adding a second file to the directory causes an access issue. Occasionally, the first file doesn't even parse. There is only one application running and watching this directory. Eventually, this process will be running on multiple machines and they will be watching a shared directory but only one server can parse each file as the data is imported into a database and there are no primary keys.

这是 FileSystemWatcher 代码:

Here is the FileSystemWatcher code:

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);
}

然后是解析文件的方法:

Then the method that parses the file:

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());
  }

移动第二个文件时,它正在捕捉

When moving the second file, it is catching

System.IO.IOException: 进程无法访问文件C:TempTestFile.txt",因为它正被另一个进程使用.

System.IO.IOException: The process cannot access the file 'C:TempTestFile.txt' because it is being used by another process.

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

I would expect to see this error if it was running on multiple machines, but it is only running on one server for now. There shouldn't be another process using this file - I have them created and copy them into the directory when the application is running.

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

Is this the proper way to set up the FileSystemWatcher? How can I see what has the lock on this file? Why doesn't it parse both files - do I have to close the FileStream? I want to keep the FileShare.None option because I only want one server to parse the file - the server that gets to the file first parses it.

推荐答案

这种方法的一个典型问题是在触发事件时文件仍在被复制.很明显,你会得到一个异常,因为文件在复制过程中被锁定.大文件尤其可能出现异常.

A typical problem of this approach is that the file is still being copied while the event is triggered. Obviously, you will get an exception because the file is locked during copying. An exception is especially likely on large files.

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

As a workaround you could first copy the file and then rename it and listen to the renaming event.

或者另一种选择是使用 while 循环检查文件是否可以使用写访问权限打开.如果可以,您将知道复制已完成.C# 代码可能如下所示(在生产系统中,您可能希望有最大重试次数或超时次数,而不是 while(true)):

Or another option would be to have a while loop checking whether the file can be opened with write access. If it can you will know that copying has been completed. C# code could look like this (in a production system you might want to have a maximum number of retries or timeout instead of a 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 只会监听触发文件.

Yet another approach would be to place a small trigger file in the folder after copying is completed. Your FileSystemWatcher would listen to the trigger file only.

这篇关于将多个文件添加到目录时,FileSystemWatcher 出现文件访问错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆