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个进程可以从同一个文件中一起读取,但只有一个应该写入,在受控方案中,您甚至可以启用并发写入,但这不能在本答案中的几个文本段落中进行概括.
是否可以解锁其他进程使用的文件?它并不总是安全且不那么容易,但是,是的,它是可能的.
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
上传图片时出现问题但无法删除并找到解决方案.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)
正如该线程中的其他答案所指出的,要解决此错误,您需要仔细检查代码,以了解文件被锁定的位置。
就我而言,在执行移动操作之前,我将文件作为电子邮件附件发送出去。
因此文件被锁定几秒钟,直到 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 次 |
最近记录: |