我有一些代码,当它执行时,它抛出一个IOException,说

进程无法访问文件'filename',因为它正在被 另一个进程

这意味着什么?我能做些什么?


当前回答

使用FileShare修复了我打开文件的问题,即使它被另一个进程打开。

using (var stream = File.Open(path, FileMode.Open, FileAccess.Write, FileShare.ReadWrite))
{
}

其他回答

我有一个非常具体的情况,我得到了一个“IOException:进程不能访问文件'文件路径'”的行

File.Delete(fileName);

在一个NUnit测试中,看起来像这样:

Assert.Throws<IOException>(() =>
{
    using (var sr = File.OpenText(fileName) {
        var line = sr.ReadLine();
    }
});
File.Delete(fileName);

NUnit 3使用了所谓的“隔离上下文”来进行异常断言。这可能运行在一个单独的线程上。

我的解决办法是把文件。在同一上下文中删除。

Assert.Throws<IOException>(() =>
{
    try
    {
        using (var sr = File.OpenText(fileName) {
            var line = sr.ReadLine();
        }
    }
    catch
    {
        File.Delete(fileName);
        throw;
    }
});

我有下面的场景会导致同样的错误:

上传文件到服务器 然后在旧文件上传后删除它们

大多数文件都很小,但也有少数文件很大,因此试图删除这些文件会导致无法访问文件的错误。

然而,要找到这个问题并不容易,解决方法很简单,就是“等待任务完成执行”:

using (var wc = new WebClient())
{
   var tskResult = wc.UploadFileTaskAsync(_address, _fileName);
   tskResult.Wait(); 
}

原因是什么?

错误消息非常清楚:您试图访问一个文件,但它无法访问,因为另一个进程(甚至是相同的进程)正在对它做一些事情(并且它不允许任何共享)。

调试

它可能很容易解决(也可能很难理解),这取决于您的具体场景。让我们看看。

您的进程是唯一访问该文件的进程 你确定另一个过程是你自己的过程。如果您知道您在程序的另一部分打开了该文件,那么首先您必须检查在每次使用后是否正确地关闭了文件句柄。下面是这个错误的代码示例:

var stream = new FileStream(path, FileAccess.Read);
var reader = new StreamReader(stream);
// Read data from this file, when I'm done I don't need it any more
File.Delete(path); // IOException: file is in use

幸运的是,FileStream实现了IDisposable,所以很容易将所有代码包装在using语句中:

using (var stream = File.Open("myfile.txt", FileMode.Open)) {
    // Use stream
}

// Here stream is not accessible and it has been closed (also if
// an exception is thrown and stack unrolled

此模式还将确保在异常情况下文件不会保持打开状态(这可能是文件正在使用的原因:出错了,没有人关闭它;请看这篇文章的例子)。

If everything seems fine (you're sure you always close every file you open, even in case of exceptions) and you have multiple working threads, then you have two options: rework your code to serialize file access (not always doable and not always wanted) or apply a retry pattern. It's a pretty common pattern for I/O operations: you try to do something and in case of error you wait and try again (did you ask yourself why, for example, Windows Shell takes some time to inform you that a file is in use and cannot be deleted?). In C# it's pretty easy to implement (see also better examples about disk I/O, networking and database access).

private const int NumberOfRetries = 3;
private const int DelayOnRetry = 1000;

for (int i=1; i <= NumberOfRetries; ++i) {
    try {
        // Do stuff with file
        break; // When done we can break loop
    }
    catch (IOException e) when (i <= NumberOfRetries) {
        // You may check error code to filter some exceptions, not every error
        // can be recovered.
        Thread.Sleep(DelayOnRetry);
    }
}

请注意我们在StackOverflow上经常看到的一个常见错误:

var stream = File.Open(path, FileOpen.Read);
var content = File.ReadAllText(path);

在这种情况下,ReadAllText()将失败,因为文件正在使用中(前一行为file . open())。事先打开文件不仅没有必要,而且是错误的。这同样适用于所有不返回您正在处理的文件句柄的文件函数:File. readalltext (), File. writealltext (), File. readalllines (), File. writealllines()和其他(如File. appendallxyz()函数)都将自行打开和关闭文件。

您的进程并不是唯一访问该文件的进程 如果您的进程不是唯一访问该文件的进程,那么交互就会更加困难。重试模式将有所帮助(如果文件不应该被其他人打开,但它却被打开了,那么您需要一个像Process Explorer这样的实用程序来检查谁正在做什么)。

避免的方法

如果适用,总是使用using语句打开文件。如前一段所述,它将积极地帮助您避免许多常见错误(关于如何不使用它的示例,请参阅这篇文章)。

如果可能的话,尝试决定谁拥有对特定文件的访问权,并通过一些众所周知的方法集中访问权。例如,如果您有一个用于程序读取和写入的数据文件,那么您应该将所有I/O代码装入单个类中。这将使调试更容易(因为您总是可以在那里放置一个断点,并查看谁在做什么),而且它将成为多个访问的同步点(如果需要)。

不要忘记I/O操作总是会失败,一个常见的例子是:

if (File.Exists(path))
    File.Delete(path);

如果有人在file . exists()之后但在file . delete()之前删除文件,那么它将在一个你可能错误地认为安全的地方抛出IOException。

只要可能,就应用重试模式,如果您正在使用FileSystemWatcher,则考虑延迟操作(因为您会收到通知,但应用程序可能仍在专门处理该文件)。

先进的场景 这并不总是那么容易,所以您可能需要与其他人共享访问权限。例如,如果你要从头读到尾写,你至少有两种选择。

1)使用适当的同步函数共享相同的FileStream(因为它不是线程安全的)。请看这个和这个帖子的例子。

2)使用FileShare枚举命令操作系统允许其他进程(或你自己进程的其他部分)并发访问同一个文件。

using (var stream = File.Open(path, FileMode.Open, FileAccess.Write, FileShare.Read))
{
}

In this example I showed how to open a file for writing and share for reading; please note that when reading and writing overlaps, it results in undefined or invalid data. It's a situation that must be handled when reading. Also note that this doesn't make access to the stream thread-safe, so this object can't be shared with multiple threads unless access is synchronized somehow (see previous links). Other sharing options are available, and they open up more complex scenarios. Please refer to MSDN for more details.

一般来说,N个进程可以一起从同一个文件中读取,但只有一个进程应该写入,在受控的情况下,你甚至可以启用并发写入,但这不能在这个答案中的几个文本段落中普遍化。

是否可以解锁另一个进程使用的文件?这并不总是安全的,也不那么容易,但是的,这是可能的。

我得到这个错误是因为我在执行File。移动到没有文件名的文件路径时,需要在目标中指定完整路径。

我遇到了这个问题,通过下面的代码解决了这个问题

var _path=MyFile.FileName;
using (var stream = new FileStream
    (_path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
  { 
    // Your Code! ;
  }