7

一点背景知识:在对大文件进行 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();
4

2 回答 2

12

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

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

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

答案是文档没有对违反规则会发生什么做出任何具体保证。无论如何,呼叫都可能起作用。无论如何,电话可能会奏效,但仅在偶数年的 9 月。无论如何调用都可能会发生,但前提是内存地址是 4 的倍数。(这可能取决于读取操作中涉及的特定硬件和设备驱动程序。仅仅因为它在您的机器上工作不会'不是说它适用于其他任何人。)

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

于 2012-09-11T22:36:46.813 回答
2

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

于 2016-04-28T14:04:18.933 回答