文件正在被另一个进程使用。

10

我有一个程序大致如下:

  1. 打开要读取的文件。
  2. 关闭该文件。
  3. 启动一个文件监视器以监视文件更改。
  4. 一旦检测到更改,文件监视器的EnableRaisingEvents标志将设置为false,并从步骤1重新开始。

问题是,在从步骤4返回步骤1之后,无法读取该文件,显示它正在被另一个进程使用。

我收到的错误信息:

Unhandled Exception: System.IO.IOException: The process cannot access the file 'c:\test.xml' because it is being used by another process.

出了什么问题?我的程序中步骤1的读取器仍然保持着对该文件的打开状态吗?还是某个完全不同的进程正在访问该文件?或者是文件监视器在从步骤4移动到步骤1后仍在监视该文件,尽管已将标志设置为false?


你能发布一下你的代码吗?这样有助于我们回答你的问题。 - Kevin LaBranche
1
发布一些代码。帮助我们帮助你。 - Bob G
1
代码有点庞大且保密,因为它是为一家金融公司编写的,但我会尽力确保其安全并发布。 - Ayush
也许您应该发布一些代码(只需打开和关闭文件的部分)。也许您的程序仍然保持文件处于打开状态,或者可能是FileWatcher的原因。 - JohnB
很有可能你在第一步的代码中锁定了文件,我建议先检查那里。 - BlackTigerX
7个回答

9
如果你的代码类似于这样:
[STAThread]
static void Main(string[] args)
{
    string file = "temp.txt";
    ReadFile(file);
    FileSystemWatcher fswatcher = new FileSystemWatcher(".\\");
    fswatcher.Changed += delegate(object sender, FileSystemEventArgs e)
                             {
                                 ReadFile(e.FullPath);
                             };
    while (true)
    {
        fswatcher.WaitForChanged(WatcherChangeTypes.Changed);
    }
}
private static void ReadFile(string file)
{
    Stream stream = File.OpenRead(file);
    StreamReader streamReader = new StreamReader(stream);
    string str = streamReader.ReadToEnd();
    MessageBox.Show(str);
    streamReader.Close();
    stream.Close();
}

如果您是通过记事本编辑文件,那么当您单击保存按钮时,它会保持文件处于打开状态,而如果您只是关闭程序并点击保存,则不会这样。我不知道这是记事本的一个错误还是未记录的功能,但这可能就是您的问题所在。修复此问题的一种方法是执行以下操作:
在您的匿名委托中或任何执行对 ReadFile() 的调用的地方,调用 Thread.Sleep(1000),以便程序在读取文件之前等待,这样您的代码应该可以正常工作。

@xbonez:这段代码对我来说很好用,即使没有Thread.Sleep()也可以。 (我将MessageBox.Show更改为Console.WriteLine)但是,我仍然会使用using语句。 - JohnB
在进一步尝试后,我发现如果我有两个实例的程序同时监视同一个文件,当我在记事本中点击“保存”时,其中一个实例会出现以下错误(另一个继续运行):The process cannot access the file 'c:\file.txt' because it is being used by another process. - JohnB
在进一步的尝试中,我发现即使只运行一个文件监视器程序,有时也会出现“进程无法访问文件”的错误。因此,在delegate中的ReadFile(e.FullPath)之前加入了Thread.Sleep(500),现在它运行得非常好。我现在拥有了一个强大的小型文件监视器程序:+1 Richard :) - JohnB

4
你可以使用类似于Process Explorer的工具来查看哪个进程持有该进程的打开句柄。很可能是由于触发更改通知的原因导致文件被持续打开。

3
注意:即使“file.txt”在记事本中打开,此代码仍然有效,因为它是以只读方式打开的。
using System;
using System.IO;

class Program
{
  static void Main(string[] args)
  {
    ReadFromFile(@"C:\file.txt");
    Console.ReadLine();
  }

  static void ReadFromFile(string filename)
  {
    string line;
    using (StreamReader sr = File.OpenText(filename))
    {
      line  = sr.ReadLine();
      while (line != null)
      {
        Console.WriteLine(str);
        line = sr.ReadLine();
      }
      sr.Close();
    }
  }
}

或者只需:

string text = System.IO.File.ReadAllText(@"C:\file.txt");



3
除了其他回答之外,当 FileWatcher 检测到文件时,可能该应用程序尚未关闭该文件。在第一步中,请尝试不立即失败,而是尝试几次,每次延迟一小段时间。

1

0
你可以使用微软工具 openfiles 来获取打开文件的列表,并了解是谁打开了文件。
openfiles /query

同时它也允许断开被网络用户打开的文件。

openfiles /disconnect /id XXXX

如果您想在本地计算机上使用它,您应该设置Maintain Objects List全局标志:

openfiles /local on

请点击链接以获取更多详细信息。


0

可能有几种情况。

首先,请确保正确处理文件写入器(仅关闭不足够),通过在实现IDisposable的所有对象周围使用using子句。

其次,如果只是读取文件,请确保在打开文件时设置了正确的标志。

如果您提供一个代码块,显示您是如何完成这个操作的,那将有助于我们更进一步地解决问题,特别是关于文件读取方面。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接