我有一段简单的代码:
File.WriteAllBytes(Path.Combine(temp, node.Name), stuffFile.Read(0, node.FileHeader.FileSize));
有人会认为WriteAllBytes
将是一个阻塞调用,因为它在C#5.0中具有异步对应,并且它在任何MSDN文档中都没有声明它是非阻塞的。然而,当一个文件大小合适(不是很大,但在20mb的范围内的某个地方)之后打开文件的调用似乎在写入完成之前被调用,并且文件被打开(程序抱怨它已损坏,这是正确的)然后WriteAllBytes
抱怨文件在另一个进程中打开。这里发生了什么?!出于好奇的缘故,这是用于打开文件的代码:
System.Diagnostics.Process.Start(Path.Combine(temp, node.Name));
之前有人经历过这种奇怪吗?或者我是一个金发女郎并做错了什么?
如果确实存在阻塞,可能导致此问题的原因是什么?
编辑:我会完整的方法。
var node = item.Tag as FileNode;
stuffFile.Position = node.FileOffset;
string temp = Path.GetTempPath();
File.WriteAllBytes(Path.Combine(temp, node.Name), stuffFile.Read(0, node.FileHeader.FileSize));
System.Diagnostics.Process.Start(Path.Combine(temp, node.Name));
似乎正在发生的事情是Process.Start
正在被调用WriteAllBytes
完成,并且它试图打开文件,然后WriteAllBytes
抱怨另一个持有锁定的进程文件。
答案 0 :(得分:6)
不,WriteAllBytes是一种阻塞的同步方法。如你所说,如果不是,那么文件会这样说。
病毒扫描程序可能仍在忙于扫描您刚编写的文件,并负责锁定文件。尝试暂时禁用扫描仪来测试我的假设。
答案 1 :(得分:1)
我认为您的问题可能与您从文件中读取的方式有关。请注意,Stream.Read
(和FileStream.Read
)不需要阅读您的所有请求。
换句话说,你的调用stuffFile.Read(0, node.FileHeader.FileSize)
可能(有时肯定会)返回一个node.FileHeader.FileSize
数组,其中包含文件开头的一些字节,然后是0之后。
该错误发生在UsableFileStream.Read
方法中。您可以通过将整个文件读入内存来修复它:
public byte[] Read(int offset, int count)
{
// There are still bugs in this method, like assuming that 'count' bytes
// can actually be read from the file
byte[] temp = new byte[count];
int bytesRead;
while ( count > 0 && (bytesRead = _stream.Read(temp, offset, count)) > 0 )
{
offset += bytesRead;
count -= bytesRead;
}
return temp;
}
但由于您只是使用它来复制文件内容,因此您可以避免进行这些潜在的大量分配并在Stream.CopyTo
中使用tree_MouseDoubleClick
:
var node = item.Tag as FileNode;
stuffFile.Position = node.FileOffset;
string temp = Path.GetTempPath();
using (var output = File.Create(Path.Combine(temp, node.Name)))
stuffFile._stream.CopyTo(output);
System.Diagnostics.Process.Start(Path.Combine(temp, node.Name));
答案 2 :(得分:0)
有点晚了,但为了其他可能出现的人的利益而添加。
File.WriteAllBytes 的底层 C# 实现可能是同步的,但 C# 的作者无法在操作系统级别控制如何处理写入磁盘。
所谓的写缓存意味着当 C# 要求将文件保存到磁盘时,操作系统可能会在文件完全写入磁盘之前返回“我完成了”,从而导致问题 OP 突出显示。
在这种情况下,在写入之后,最好在循环中休眠并在调用 Process.Start 之前继续检查文件是否仍然被锁定。
你可以看到我在这里遇到了由此引起的问题:C#, Entity Framework Core & PostgreSql : inserting a single row takes 20+ seconds
此外,在 OP 帖子的最后一句中,“然后 WriteAllBytes 抱怨另一个进程持有文件锁定。”我认为他们实际上是想写“然后 Process.Start 抱怨”,这似乎在评论中引起了一些混乱。