首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ReadFile Kernel32最大缓冲区大小

ReadFile Kernel32最大缓冲区大小
EN

Stack Overflow用户
提问于 2011-10-04 10:13:35
回答 4查看 7.1K关注 0票数 1

我正在使用C#直接从磁盘读取数据,并调用kernel32 ReadFile方法。我注意到,对于较大的读取(目前只以单个块读取),缓冲区大小超出了范围。

有人知道这里读取缓冲区的最大大小吗?

如果是这样的话,当我有我想要读入的剩余内存时,限制缓冲区大小的目的是什么?我理解缓冲和保持小内存占用的概念,但是为什么一个小的大小强加在我们身上呢?也许只是一个旧的Win32 API的伪制品?

编辑:从Marshal.GetLastWin32Error()收到的错误是“值不属于预期范围”。

在收到此错误之前,上限为8192字节(8KB --因此我感到困惑)。

代码语言:javascript
复制
using System;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;

namespace DiskRead
{
    class Program
    {
        public const uint GenericRead = 0x80000000;
        public const uint FileShareRead = 1;
        public const uint FileShareWrite = 2;
        public const uint OpenExisting = 3;

        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        private static extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess,
          uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition,
          uint dwFlagsAndAttributes, IntPtr hTemplateFile);

        [DllImport("kernel32.dll", SetLastError = true)]
        static extern bool ReadFile(IntPtr hFile, [Out] byte[] lpBuffer,
           uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, IntPtr lpOverlapped);

        static void Main(string[] args)
        {
            string path = @"\\.\PhysicalDrive0";

            IntPtr ptr = CreateFile(path, GenericRead, FileShareRead | FileShareWrite, IntPtr.Zero, OpenExisting, 0, IntPtr.Zero);

            SafeFileHandle handleValue = new SafeFileHandle(ptr, true);
            FileStream fileStream = new FileStream(handleValue, FileAccess.Read);

            const uint numberOfBytesToRead = 8193;

            uint bytesRead;
            byte[] buffer = new byte[numberOfBytesToRead];


            if (!ReadFile(handleValue.DangerousGetHandle(), buffer, numberOfBytesToRead, out bytesRead, IntPtr.Zero))
            {
                Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
            }

        }
    }
}

提前谢谢。

EN

回答 4

Stack Overflow用户

发布于 2011-10-04 13:29:57

没有这样的限制。你搞错了。

显然,您受到地址空间和缓冲区是一个连续的虚拟内存块的要求的限制。在32位系统上,每个进程只能处理2GB的虚拟内存。此外,您将无法分配2GB的连续内存块。

但这些都是普遍的限制。ReadFile API将很高兴地读入尽可能大的缓冲区中。

您声称达到了8KB的限制,但是我刚刚成功地使用WriteFileReadFile编写和读取了一个1GB的文件。很明显,你有一些问题,但这并不是你想的那样。如果您能够显示其余的代码,特别是调用p/ code的代码,那么我肯定它会变得很明显。

现在,您已经发布了完整的代码,我们可以看到问题是什么。您不是在读取文件,而是在执行物理磁盘的读取。我明白了,这就是你所说的“直接从磁盘读取”的意思,但我认为你可以说得更具体一点!

无论如何,我不知道这里发生了什么,但问题显然不是ReadFile本身,而是您的句柄是物理磁盘而不是文件。

CreateFile的文档声明:

卷包含一个或多个挂载的文件系统。即使在CreateFile中未指定非缓存选项时,也可以根据特定文件系统的决定以非缓存的形式打开卷句柄。您应该假设所有Microsoft文件系统都以非缓存的形式打开卷句柄。对文件的非缓存I/O的限制也适用于卷。 即使数据是非缓存的,文件系统可能需要也可能不需要缓冲区对齐。但是,如果在打开卷时指定了非缓存选项,则不管卷上的文件系统如何,缓冲区对齐都是强制的。建议在所有以非缓存的形式打开卷处理的文件系统上,并遵循非缓存的I/O限制。

我认为你应该考虑问一个关于如何从物理磁盘中读取的新问题。

票数 1
EN

Stack Overflow用户

发布于 2011-10-07 01:07:08

我不确定这是否对你有帮助,但它可能对其他读者有帮助:

  1. 当涉及到ReadFile()时,它的行为和成功在很大程度上取决于如何用CreateFile()打开文件。为了给您一个正确的方向,请考虑这一点;当您调用CreateFile()到缓冲区读取时,通常不会想要FILE_FLAG_NO_BUFFERING,除非您已经准备好处理数据对齐问题,并且对一些特定于硬件的信息进行了很好的绕道,尽管这可能更容易避免。
  2. 您的代码似乎没有做到这一点,但是它是互操作的,因此可能会有一个错误的值从某个地方得到,而.NET以骚扰(?)内存块,因此您可能需要尝试通过互操作分配内存,以确保内存块不会移动到任何地方。而且,我会尽量减少互操作,在最需要它的时候,它似乎有点不可靠。相反,您可以考虑编写一个DLL,以便更好地处理代码,并将其互操作。我在很多情况下都这样做过,而且它运行得很好,并且增加了不需要编写相同的代码,只需在任意多个程序中重用它的好处。至于你的问题的根本原因,我无法复制它自己,我试过的最大的文件是大约800 ok,它打开,读,关闭好.您能否提供源代码,以便由其他人(或非常冗长的构建可执行文件)进行测试,以查看其他人是否存在相同的问题?希望这能帮上忙。

资源

  • CreateFile() ReadFile()来自MSDN 2011文档 (备注第9和13段)
  • 文件缓冲 缓冲区大小和扇区对齐的限制进一步注意,建议使用VirtualAlloc()获取对齐的内存块。
票数 1
EN

Stack Overflow用户

发布于 2011-10-04 11:08:32

不确定要读入的缓冲区的最大大小,但缓冲区大小的根本原因是,在函数内部,可以进行检查,这样缓冲区结束后就不会写入任何数据。如果函数没有输入缓冲区大小的概念,它可以写入缓冲区的末尾,从而导致缓冲区溢出。那将是一个严重的安全漏洞。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7646320

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档