IOException:进程无法访问文件"文件路径",因为它正由另一个进程使用

Adr*_*tti 152 .net c# language-agnostic ioexception

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

该进程无法访问文件'filename',因为它正由另一个进程使用

这是什么意思,我能做些什么呢?

Adr*_*tti 249

原因是什么?

错误消息非常清楚:您正在尝试访问文件,并且它无法访问,因为另一个进程(甚至同一进程)正在使用它(并且它不允许任何共享).

调试

根据您的具体情况,它可能很容易解决(或很难理解).我们来看看吧.

您的进程是唯一访问该文件
的进程您确定其他进程是您自己的进程.如果您知道在程序的其他部分打开该文件,那么首先必须检查每次使用后是否正确关闭文件句柄.以下是此错误的代码示例:

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
Run Code Online (Sandbox Code Playgroud)

幸运的是,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
Run Code Online (Sandbox Code Playgroud)

此模式还将确保在异常情况下文件不会保持打开状态(这可能是文件正在使用的原因:出现问题,没有人关闭它;请参阅此帖子以获取示例).

如果一切看起来都很好(你确定你总是关闭你打开的每个文件,即使出现例外情况)并且你有多个工作线程,那么你有两个选择:重新编写代码以序列化文件访问(并不总是可行而不是总是想要)或应用重试模式.这是I/O操作的一种非常常见的模式:您尝试做某事并在出现错误时等待并再试一次(例如,您是否问自己为什么,Windows Shell需要一些时间来通知您文件正在使用中并且不能删除?).在C#中,它很容易实现(另请参阅有关磁盘I/O,网络数据库访问的更好示例).

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

var stream = File.Open(path, FileOpen.Read);
var content = File.ReadAllText(path);
Run Code Online (Sandbox Code Playgroud)

在这种情况下,ReadAllText()将失败,因为文件正在使用中(File.Open()在之前的行中).预先打开文件不仅是不必要的,而且也是错误的.这同样适用于所有File不回报功能句柄到你正在使用的文件:File.ReadAllText(),File.WriteAllText(),File.ReadAllLines(),File.WriteAllLines()和其他人(如File.AppendAllXyz()函数)将全部开放,并自行关闭文件.

您的进程不是唯一访问该文件
的进程如果您的进程不是唯一访问该文件的进程,那么交互可能会更难.一个重试模式将帮助(如果该文件不应该由任何人打开,但它是,那么你需要像Process Explorer的一个实用程序,检查在做什么).

方法避免

如果适用,请始终使用using语句打开文件.如前一段所述,它会主动帮助您避免许多常见错误(有关如何不使用它的示例,请参阅此文章).

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

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

if (File.Exists(path))
    File.Delete(path);
Run Code Online (Sandbox Code Playgroud)

如果有人在之后File.Exists()但之前删除了该文件File.Delete(),那么它会IOException在一个您可能错误地感到安全的地方扔掉.

只要有可能,应用重试模式,如果您正在使用FileSystemWatcher,请考虑推迟操作(因为您将收到通知,但应用程序可能仍在使用该文件).

高级方案
并非总是如此简单,因此您可能需要与其他人共享访问权限.例如,如果您从头开始阅读并写到结尾,则至少有两个选项.

1)FileStream与适当的同步功能共享相同的功能(因为它不是线程安全的).看到这个这个帖子的一个例子.

2)使用FileShare枚举来指示OS允许其他进程(或您自己进程的其他部分)同时访问同一文件.

using (var stream = File.Open(path, FileMode.Open, FileAccess.Write, FileShare.Read))
{
}
Run Code Online (Sandbox Code Playgroud)

在这个例子中,我展示了如何打开文件进行编写和共享以供阅读; 请注意,在读取和写入重叠时,会导致数据未定义或无效.这是一种必须在阅读时处理的情况.另请注意,这不会访问stream线程安全,因此除非以某种方式同步访问,否则无法与多个线程共享此对象(请参阅前面的链接).可以使用其他共享选项,它们可以打开更复杂的场景.有关更多详细信息,请参阅MSDN.

一般来说,N个进程可以从同一个文件中一起读取,但只有一个应该写入,在受控方案中,您甚至可以启用并发写入,但这不能在本答案中的几个文本段落中进行概括.

是否可以解锁其他进程使用的文件?它并不总是安全且不那么容易,但是,是的,它是可能的.

  • @جمشیدکامران为什么要创建一个包含代码中的内容的文件,然后将其删除?然后,首先创建文件似乎很奇怪.由于您没有发布代码,我们不知道您在做什么.但是当你创建你的文件时,如果用`File.Create(path)`来做,你应该在写它之前在它的末尾添加`.Close()`.除了使用`using`语句写入文件,然后在它们之后删除之外,还有类似的缺陷.您应该在问题中发布代码,以了解如何创建和删除文件.但可能与上面提到的内容一致. (2认同)

Muh*_*mar 18

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

using (var stream = File.Open(path, FileMode.Open, FileAccess.Write, FileShare.ReadWrite))
{
}
Run Code Online (Sandbox Code Playgroud)


han*_*nan 17

问题

一个人正在使用此方法打开文件System.IO.File.Open(path, FileMode)并希望对文件进行共享访问,但是

如果您阅读System.IO.File.Open(path, FileMode)的文档,它明确表示它不允许共享

在此输入图像描述

解决方案

使用时您必须使用FileShare 的其他覆盖 在此输入图像描述

using FileStream fs = System.IO.File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
Run Code Online (Sandbox Code Playgroud)

FileShare.Read

  • 抱歉,我们[无法接受代码、数据、文档或错误的图像](https://meta.stackoverflow.com/a/285557)。将它们发布为*文本*,以便文本可读,而无需重新输入所有内容,并且您的帖子可以正确索引或由屏幕阅读器阅读。 (3认同)

Hud*_*son 7

上传图片时出现问题但无法删除并找到解决方案.gl hf

//C# .NET
var image = Image.FromFile(filePath);

image.Dispose(); // this removes all resources

//later...

File.Delete(filePath); //now works
Run Code Online (Sandbox Code Playgroud)

  • 如果要删除文件,则需要先处理图像对象。 (2认同)
  • 这对我来说非常有效,解决了我的确切问题。我想处理 Tiff 文件的文件夹,将它们转换为 byte[] 流并发送到服务,然后将 Tiff 文件的文件夹移动到“已处理”存档文件夹。Image.FromFile 在 Tiff 文件上放置了一个锁,并且没有及时释放它,因此当我去移动 Tiff 文件和包含文件夹时,我会收到“正在被另一个进程使用”错误,因为锁仍然存在到位。在获取 Tiff 文件的字节后立即执行 .Release 完全解决了此锁定文件问题。 (2认同)

Abh*_*ary 6

正如该线程中的其他答案所指出的,要解决此错误,您需要仔细检查代码,以了解文件被锁定的位置。

就我而言,在执行移动操作之前,我将文件作为电子邮件附件发送出去。

因此文件被锁定几秒钟,直到 SMTP 客户端完成发送电子邮件为止。

我采用的解决方案是先移动文件,然后发送电子邮件。这为我解决了问题。

正如哈德森之前指出的,另一种可能的解决方案是在使用后处理该物体。

public static SendEmail()
{
           MailMessage mMailMessage = new MailMessage();
           //setup other email stuff

            if (File.Exists(attachmentPath))
            {
                Attachment attachment = new Attachment(attachmentPath);
                mMailMessage.Attachments.Add(attachment);
                attachment.Dispose(); //disposing the Attachment object
            }
} 
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

421661 次

最近记录:

6 年,2 月 前