File.WriteAllBytes不会阻止

时间:2013-05-25 04:52:17

标签: c# .net file-io

我有一段简单的代码:

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抱怨另一个持有锁定的进程文件。

3 个答案:

答案 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 抱怨”,这似乎在评论中引起了一些混乱。