Handle不支持CreateFile的同步操作

时间:2012-09-26 18:33:03

标签: c# .net winapi createfile

我需要在原始模式下打开读取磁盘,因此我正在使用CreateFile API函数。

private static FileStream OpenDisk(string drive)
{
    // Try to open hard disk drive in raw mode for reading
    SafeFileHandle safeHandle = Native.CreateFile(
        string.Format(@"\\.\{0}", drive),
        FileAccess.Read,
        FileShare.Read,
        IntPtr.Zero,
        FileMode.Open,
        FileAttributes.ReadOnly | FileAttributes.Device,
        IntPtr.Zero);

    // Check if the drive was successfully opened
    if (safeHandle.IsInvalid)
    {
        Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
    }

    // Create file stream on the file for reading
    return new FileStream(safeHandle, FileAccess.Read);
}

但是当我尝试从流中读取时,我收到以下错误

Handle does not support synchronous operations. The parameters to the FileStream constructor may need to be changed to indicate that the handle was opened asynchronously (that is, it was opened explicitly for overlapped I/O).

以下是重现此问题的示例代码

using (FileStream stream = OpenDisk("X:"))
{
    byte[] buffer = new byte[1000];
    while (stream.Read(buffer, 0, 1000) > 0) { }
}

我真的不知道它对我有什么要求?当我使用更大的缓冲区(例如4096)时,它可以工作。当我说它工作时我的意思是它真的有效(总是),它工作了一段时间,直到我改变了缓冲区大小。我猜它里面有一些异步缓冲,当我指定更大的缓冲区然后默认缓冲大小它只是没用过,但是如何摆脱这个?

由于

更新

当我尝试使用BufferedStream读取它时,我遇到了同样的问题

using (BufferedStream stream = new BufferedStream(OpenDisk("X:"), 4096))
{
    byte[] buffer = new byte[1000];
    while (stream.Read(buffer, 0, 1000) > 0) { }
}

我是否了解BufferedStream的错误用途?它不应该读取和缓存指定大小的块吗?

1 个答案:

答案 0 :(得分:4)

简而言之,来自卷的读取是非缓冲的,必须是整个扇区。缓冲区大小为4096实现了这一点。错误消息具有误导性,因为异步I / O和非缓冲往往会在一起。一些细节:

来自CreateFile docs

即使未在CreateFile中指定非高速缓存选项,也可以根据特定文件系统的判断将卷句柄打开为非高速缓存。您应该假设所有Microsoft文件系统都将未处理的卷句柄打开。对文件的非高速缓存I / O的限制也适用于卷。

来自File Buffering docs

  • 文件访问大小(包括OVERLAPPED结构中的可选文件偏移量,如果指定)必须是多个字节,它是卷扇区大小的整数倍。例如,如果扇区大小为512字节,则应用程序可以请求读取和写入512,1024,1,536或2,048字节,但不能请求335,981或7,171字节。
  • 读取和写入操作的文件访问缓冲区地址应该是物理扇区对齐的,这意味着在内存中的地址上对齐,该地址是卷的物理扇区大小的整数倍。根据磁盘的不同,可能不会强制执行此要求。