用FileStream和FILE_FLAG_NO_BUFFERING读取文件

一点背景:我一直在用大文件做IO时使用FILE_FLAG_NO_BUFFERING标志进行试验。 我们试图减lesscachingpipe理器的负载,希望通过后台IO,我们将减less我们的应用程序在用户机器上的影响。 性能不是问题。 尽可能地在幕后进行是一个大问题。 我有一个接近工作的包装,做无缓冲IO,但我遇到了一个奇怪的问题。 当我调用Read的偏移量不是4的倍数时,我得到这个错误。

手柄不支持同步操作。 可能需要更改FileStream构造函数的参数,以指示该句柄是asynchronous打开的(也就是说,它是针对重叠的I / O显式打开的)。

为什么会这样呢? 这个消息是不是矛盾呢? 如果我添加asynchronous文件选项,我得到一个IOException(参数不正确。)

我想真正的问题是什么这些要求, http://msdn.microsoft.com/en-us/library/windows/desktop/cc644950%28v=vs.85%29.aspx ,必须做这些倍数4。

这是演示这个问题的代码:

FileOptions FileFlagNoBuffering = (FileOptions)0x20000000; int MinSectorSize = 512; byte[] buffer = new byte[MinSectorSize * 2]; int i = 0; while (i < MinSectorSize) { try { using (FileStream fs = new FileStream(@"<some file>", FileMode.Open, FileAccess.Read, FileShare.None, 8, FileFlagNoBuffering | FileOptions.Asynchronous)) { fs.Read(buffer, i, MinSectorSize); Console.WriteLine(i); } } catch { } i++; } Console.ReadLine(); 

当使用FILE_FLAG_NO_BUFFERING ,文档化的要求是读或写的内存地址必须是物理扇区大小的倍数。 在你的代码中,你已经允许随机选择字节数组的地址(因此不太可能是物理扇区大小的倍数),然后添加一个偏移量。

你所观察到的行为是,如果偏移量是4的倍数,调用就可以工作。字节数组可能与4字节边界对齐,所以如果内存地址是4的倍数。

因此,你的问题可以这样改写:当内存地址是4的倍数时,为什么读取工作,当文档说它必须是512的倍数?

答案是,如果违反规则,文档没有对发生的情况做出任何具体的保证。 通话可能会发生,无论如何。 不管怎么样,这个电话可能会发生作用,但是仅在偶数年的九月。 可能会发生这种情况,无论如何,只有当内存地址是4的倍数时(这可能取决于读操作中涉及的具体硬件和设备驱动程序,只是因为它在你的机器上工作,这意味着它会在任何其他人的工作。)

FileStream中首先使用FILE_FLAG_NO_BUFFERING可能不是一个好主意,因为我怀疑FileStream实际上是否确保将它未经修改的地址传递给底层的ReadFile调用。 而是使用P / Invoke直接调用底层的API函数。 你也可能需要这样分配你的内存,因为我不知道.NET是否提供了任何分配内存的方法。

只需使用FILE_FLAG_NO_BUFFERING直接调用CreateFile,然后在使用FileStream打开之前关闭它即可达到相同的效果。