使用FileStream和FILE_FLAG_NO_BUFFERING读取文件

时间:2012-09-11 21:05:51

标签: c# windows

一点背景:在使用大文件执行IO时,我一直在尝试使用FILE_FLAG_NO_BUFFERING标志。我们正在尝试减少缓存管理器的负载,希望通过后台IO,我们将减少应用程序对用户计算机的影响。性能不是问题。尽可能在幕后是一个大问题。我有一个接近工作的包装器来做无缓冲的IO,但我遇到了一个奇怪的问题。当我使用不是4的倍数的偏移量调用Read时,我收到此错误。

  

句柄不支持同步操作。可能需要更改FileStream构造函数的参数以指示句柄是异步打开的(即,它是为重叠的I / O显式打开的。)

为什么会这样?这条消息本身是否自相矛盾?如果我添加异步文件选项,我会收到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();

2 个答案:

答案 0 :(得分:11)

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

您正在观察的行为是,如果偏移量是4的倍数,则调用有效。字节数组可能与4字节边界对齐,因此如果内存地址是a,则调用正在工作4的倍数。

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

答案是,如果违反规则,文档不会对发生的情况做出任何具体保证。无论如何,呼叫可能会发生。无论如何,呼叫可能会发生,但仅在偶数年份的9月。无论如何,呼叫可能会起作用,但前提是内存地址是4的倍数。(这很可能取决于读取操作中涉及的特定硬件和设备驱动程序。只是因为它适用于您的计算机而不是'这意味着它将适用于任何其他人。)

首先将FILE_FLAG_NO_BUFFERINGFileStream一起使用可能不是一个好主意,因为我怀疑FileStream实际上是否保证它会通过您未经修改的地址传递潜在的ReadFile电话。相反,使用P / Invoke直接调用底层API函数。您可能还需要以这种方式分配内存,因为我不知道.NET是否提供了任何方式来分配具有特定对齐的内存。

答案 1 :(得分:1)

直接使用FILE_FLAG_NO_BUFFERING调用CreateFile,然后在使用FileStream打开之前将其关闭以达到相同的效果。