当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《将多个文件添加到目录时,FileSystemWatcher会出现文件访问错误》经验,为你挑选了2个好方法。

当多个文件放入监视目录时,我遇到了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选项,因为我只想要一个服务器来解析文件 - 获取文件的服务器首先解析它.



1> Dirk Vollmar..:

此方法的典型问题是在触发事件时仍在复制文件.显然,您将获得异常,因为文件在复制期间被锁定.大文件特别容易出现异常.

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

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

/// 
/// Waits until a file can be opened with write permission
/// 
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只会侦听触发器文件.


+1但是你应该有一个等待的最长时间,以便不会永久锁定进程

2> G-Mac..:

我上面已经发表评论,但我还没有足够的分数.

对这个问题的评价最高的答案有一段看起来像这样的代码:

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

使用FileShare.ReadWrite设置的问题在于它正在请求访问该文件,主要是说"我想读/写这个文件,但其他人也可以读/写它".这种方法在我们的情况下失败了 接收远程传输的进程没有锁定文件,但它正在积极地写入它.我们的下游代码(SharpZipLib)因"正在使用文件"异常而失败,因为它试图打开文件FileShare.Read("我想要读取文件,只允许其他进程读取").由于打开文件的进程已经写入,因此该请求失败.

但是,上面的响应中的代码太宽松了.通过使用FileShare.ReadWrite,它成功获得了对文件的访问权限(因为它要求可以兑现的共享限制),但下游调用仍然失败.

调用中的共享设置File.Open应为FileShare.ReadFileShare.None,而不是 FileShare.ReadWrite.

推荐阅读
臭小子
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有