Reading a file with FileStream and FILE_FLAG_NO_BUFFERING

Small background: I experimented using the FILE_FLAG_NO_BUFFERING flag while doing I / O with large files. We are trying to reduce the load on the cache manager in the hope that by using background I / O we will reduce the impact of our application on user machines. Performance is not a problem. Being behind the curtains as much as possible is a big problem. I have a compatible shell for performing unbuffered I / O, but I am having a strange problem. I get this error when I call Read with an offset that is not a multiple of 4.

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

Why is this happening? And does this message not contradict itself? If I add an asynchronous file parameter, I get an IOException (parameter is incorrect.)

I think the real question is that these requirements, http://msdn.microsoft.com/en-us/library/windows/desktop/cc644950%28v=vs.85%29.aspx , are relevant to these multiple of 4.

Here is the code that demonstrates the problem:

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
source share
2 answers

When using FILE_FLAG_NO_BUFFERING documented requirement is that the memory address to read or write must be a multiple of the size of the physical sector. In your code, you selected a random selection of the address of the byte array (therefore, it is unlikely to be a multiple of the size of the physical sector), and then you add an offset.

The behavior you observe is that the call works if the offset is a multiple of 4. Probably the byte array is aligned at the 4-byte boundary, so the call works if the memory address is a multiple of 4.

Therefore, your question can be rewritten as follows: why does reading work when the memory address is a multiple of 4, when the documentation says that it should be a multiple of 512?

The answer is that the documentation does not give any specific guarantees as to what will happen if you break the rules. It may happen that the call is all the same. It may happen that the call works anyway, but only in September in even years. It may happen that the call works in any case, but only if the memory address is a multiple of 4. (It probably depends on the specific hardware and device drivers involved in the read operation. Just because it works on your machine, t means that it will work for someone else's.)

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

+10
source

Just call CreateFile directly with FILE_FLAG_NO_BUFFERING, and then close it before opening FileStream to achieve the same effect.

-2
source

Source: https://habr.com/ru/post/1433662/


All Articles