【发布时间】:2015-09-07 07:52:04
【问题描述】:
我刚看到这个问题:Is it safe to use static methods on File class in C#?。总而言之,OP 有一个IOException,因为此 ASP.NET 代码 sn-p 中正在使用文件:
var text= File.ReadAllText("path-to-file.txt");
// Do something with text
File.WriteAllText("path-to-file.txt");
我的第一个想法是,由于多个 ASP.NET 重叠请求,这是一个简单并发访问问题。我会解决将 I/O 集中到一个同步的线程安全类(或删除文件以支持其他东西)的问题。我阅读了两个答案,当我正要对其中一个投反对票时,我看到了这些用户是谁,我想 h* 并停止了。
我会同时引用它们(然后请参阅原始答案以获取更多上下文)。
对于本 OP 段落:
我猜测文件读取操作有时不会在写入操作发生之前关闭文件[...]
回答说:
正确。文件系统不能很好地支持原子更新 [...] 使用 FileStream 无济于事 [...] 文件内部没有魔法。为了您的方便,它只是使用了 FileStream 包装。
但是我看不到任何原子操作(读取 + 后续写入)和 并行(由于部分重叠的多线程请求)可能会导致并发访问。即使是 atomic I/O 操作(读 + 写)也会有完全相同的问题。好的 FileStream 可能是异步的,但这不是 File.ReadAllText() 和 File.WriteAllText() 使用它的方式。
另一个答案让我更加困惑,它说:
虽然根据文档,此方法保证文件句柄关闭,但即使引发异常,也不能保证关闭的时间在方法返回之前发生:关闭可以异步完成。
什么? MSDN 说方法将打开、读取和关闭文件(也在异常情况下)。这种方法是否有可能异步关闭文件?操作系统会推迟CloseHandle() 吗?在哪些情况下?为什么?
简而言之:这只是一个误解还是CloseHandle()是异步的?我错过了非常重要的东西?
【问题讨论】:
-
我不同意该线程中的答案。当 Windows API 从
CloseHandle()返回时,该句柄将关闭。如果有异常,那是因为有多个线程同时访问它。由于File.ReadAllLines()最终使用CloseHandle()关闭文件,因此文件将在返回时关闭。如果这不是真的,所有的地狱都会崩溃。我很确定另一个问题中提到的错误是由于多线程问题造成的。 -
@MatthewWatson 我同意你的观点,它会破坏我们一半的代码。我问只是因为那些用户代表(以防它是一个远程无证奇怪的角落案例)。
-
事实上,如果您考虑一种用于日志文件(打开、追加、刷新、关闭)的常见模式,其中会发生非常频繁的更新,如果您不能保证可以重新打开,事情很快就会变得很糟糕关闭后不久的文件。 (可能存在涉及其他类型句柄的实例,但其工作方式不同,但对于打开单个实例的基本文件句柄,它们将确定性地关闭。)
-
@MatthewWatson 只要只有一个句柄,而且是同步的,你是对的。
FileStream将只有一个句柄,所以这很好,它也将与File.ReadXXX同步。您提到的用于日志文件的通用模式 是错误的 (关闭之前的冗余刷新是一个小例子) - 它只是错误地不足以在任何时候完全失败。就可维护性而言,这是最糟糕的错误。也就是说,在这种情况下,问题出在其他地方 - 其他东西正在触及同一个文件。这在 ASP.NET 中非常很常见。 -
文件系统是邪恶的,并且每时每刻都在密谋破坏您的代码。当面对文件系统逃跑时,像小女孩一样尖叫通常是最好的方法。