阅读使用FileStream和FILE_FLAG_NO_BUFFERING文件 [英] Reading a file with FileStream and FILE_FLAG_NO_BUFFERING

查看:190
本文介绍了阅读使用FileStream和FILE_FLAG_NO_BUFFERING文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

一个小背景:我一直在尝试与大文件做IO在使用FILE_FLAG_NO_BUFFERING标志。我们正在努力减少希望与背景的IO,我们将降低我们的应用程序的用户的机器上影响缓存管理器的负荷。性能是不是一个问题。作为幕后尽可能的背后,是一个大问题。我有一个贴近工作的包装做缓冲的IO,但我遇到了一个奇怪的问题。我得到这个错误,当我调用read与偏移不是4的倍数。




句柄不支持同步操作。到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;
字节[]缓冲区=新的字节[MinSectorSize * 2];
INT I = 0;
,而(I< MinSectorSize)
{使用

{
(的FileStream FS =新的FileStream(@<有的文件>,FileMode.Open ,FileAccess.Read,FileShare.None,8,FileFlagNoBuffering | FileOptions.Asynchronous))
{
fs.Read(缓冲,我,MinSectorSize);
Console.WriteLine(ⅰ);
}
}
赶上{}
I ++;
}
到Console.ReadLine();


解决方案

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



你观察的行为是该呼叫工作,如果偏移量为4的倍数。它是可能的字节数组对齐到4字节边界,所以该呼叫工作,如果该存储器地址,是4的倍数



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



答案是,文件并没有做出,如果你打破规则发生了什么任何具体保证。它可能发生在调用工作反正。它可能发生在调用的工作,无论如何,但只在九月偶数年。它可能发生在调用的作品,无论如何,但只有当内存地址是4的倍数(很可能,这取决于所涉及的读操作的具体硬件和设备驱动程序。只是因为它适用于你的机器没有按'故意的将别人的工作。)



这可能不是用一个好主意 FILE_FLAG_NO_BUFFERING 的FileStream 摆在首位,因为我怀疑的FileStream 实际上保证它会通过你的地址给它未修改到底层的ReadFile 电话。相反,使用P / Invoke来直接调用底层的API函数。您可能还需要这种方式分配你的记忆,因为我不知道是否.NET提供任何方式与特定的对齐或不分配内存。


A little background: I've been experimenting with using the FILE_FLAG_NO_BUFFERING flag when doing IO with large files. We're trying to reduce the load on the cache manager in the hope that with background IO, we'll reduce the impact of our app on user machines. Performance is not an issue. Being behind the scenes as much as possible is a big issue. I have a close-to-working wrapper for doing unbuffered IO but I ran into a strange issue. I get this error when I call Read with an offset that is not a multiple of 4.

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).

Why does this happen? And is doesn't this message contradict itself? If I add the Asynchronous file option I get an IOException(The parameter is incorrect.)

I guess the real question is what do these requirements, http://msdn.microsoft.com/en-us/library/windows/desktop/cc644950%28v=vs.85%29.aspx, have to do with these multiples of 4.

Here is the code that demonstrates the issue:

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();

解决方案

When using FILE_FLAG_NO_BUFFERING, the documented requirement is that the memory address for a read or write must be a multiple of the physical sector size. In your code, you've allowed the address of the byte array to be randomly chosen (hence unlikely to be a multiple of the physical sector size) and then you're adding an offset.

The behaviour you're observing is that the call works if the offset is a multiple of 4. It is likely that the byte array is aligned to a 4-byte boundary, so the call is working if the memory address is a multiple of 4.

Therefore, your question can be rewritten like this: why is the read working when the memory address is a multiple of 4, when the documentation says it has to be a multiple of 512?

The answer is that the documentation doesn't make any specific guarantees about what happens if you break the rules. It may happen that the call works anyway. It may happen that the call works anyway, but only in September on even-numbered years. It may happen that the call works anyway, but only if the memory address is a multiple of 4. (It is likely that this depends on the specific hardware and device drivers involved in the read operation. Just because it works on your machine doesn't mean it will work on anybody else's.)

It probably isn't a good idea to use FILE_FLAG_NO_BUFFERING with FileStream in the first place, because I doubt that FileStream actually guarantees that it will pass the address you give it unmodified to the underlying ReadFile call. Instead, use P/Invoke to call the underlying API functions directly. You may also need to allocate your memory this way, because I don't know whether .NET provides any way to allocate memory with a particular alignment or not.

这篇关于阅读使用FileStream和FILE_FLAG_NO_BUFFERING文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆