4

我有一段简单的代码,如下所示:

File.WriteAllBytes(Path.Combine(temp, node.Name), stuffFile.Read(0, node.FileHeader.FileSize));

有人会认为这WriteAllBytes将是一个阻塞调用,因为它在 C# 5.0 中具有 Async 对应项,并且它在任何 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抱怨另一个进程持有文件的锁。

4

3 回答 3

5

不,WriteAllBytes 是一种阻塞的同步方法。正如您所说,如果不是,文档会这样说。

可能病毒扫描器还在忙着扫描你刚刚写的文件,并负责锁定文件。尝试暂时禁用扫描仪以测试我的假设。

于 2013-05-25T05:03:29.200 回答
1

我认为您的问题可能与您从文件中读取的方式有关。请注意,Stream.Read(and 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));
于 2013-05-25T12:42:10.607 回答
0

有点晚了,但为了其他可能出现的人的利益而添加。

File.WriteAllBytes 的底层 C# 实现很可能是同步的,但 C# 的作者无法在操作系统级别控制如何处理写入磁盘的操作。

所谓的写入缓存意味着当 C# 要求将文件保存到磁盘时,操作系统可能会在文件完全写入磁盘之前返回“我完成了”,从而导致问题 OP 突出显示。

在这种情况下,写完后,最好在循环中休眠,并在调用 Process.Start 之前继续检查文件是否仍处于锁定状态。

你可以看到我在这里遇到了由此引起的问题:C#, Entity Framework Core & PostgreSql : inserting a single row takes 20+ seconds

此外,在 OPs 帖子的最后一句“然后 WriteAllBytes 抱怨另一个进程持有文件的锁”。我认为他们实际上打算写“然后 Process.Start 抱怨”,这似乎在评论中引起了一些混乱。

于 2021-04-23T00:12:12.240 回答