【问题标题】:ReadFile function returns ERROR_INVALID_PARAMETERReadFile 函数返回 ERROR_INVALID_PARAMETER
【发布时间】:2025-12-08 02:10:03
【问题描述】:

我正在尝试使用 ReadFile 功能。这是我的代码:

#define BUFFERSIZE 5

int main(int argc, char* argv[])
{
    OVERLAPPED overlapIn = {};
    HANDLE tHandle;
    char buf[BUFFERSIZE] = {};
    DWORD  lpNumberOfBytesRead;

    tHandle = CreateFile(
        L"\\\\.\\D:",
        GENERIC_READ,
        FILE_SHARE_READ,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL);

    if (tHandle == INVALID_HANDLE_VALUE)
    {
        DWORD error = GetLastError();
        assert(0);
    }

    if (ReadFile(tHandle, &buf, BUFFERSIZE - 1, &lpNumberOfBytesRead, NULL) == 0)
    {
        int error = GetLastError();
        printf("Terminal failure: Unable to read from disk.\n GetLastError=%d\n", error);
        CloseHandle(tHandle);
        return 1;
    }

GetLastError 函数返回代码 87,即 ERROR_INVALID_PARAMETER。

很明显,其中一个参数是错误的,但我不知道是哪一个,因为我尝试按照文档中所写的那样做所有事情。

【问题讨论】:

  • 我想你在第一个 if 之后得到了错误。你不能像这样简单地从驱动器号中读取。
  • 不,我不知道,我说的是 ReadFile 函数。是的,我可以从这样的驱动器中读取数据。
  • BUFFERSIZE-1 错误。当您从磁盘驱动器读取原始数据时,您不能指望文件系统缓存。支持的对齐方式取决于文件系统,4096 是一个不错的整数。您还必须在 CreateFile() 调用中指定 FILE_SHARE_WRITE。当 CreateFile() 失败时,你需要发出更多的声音,assert() 不会削减它。
  • 哇,原来如此,谢谢!
  • 从设备读取的原始数据必须是块大小的倍数。

标签: c winapi readfile


【解决方案1】:

这在documentation for CreateFile中有所描述:

卷句柄可以根据特定文件系统的判断以非缓存方式打开,即使在 CreateFile 中未指定非缓存选项也是如此。您应该假设所有 Microsoft 文件系统都以非缓存方式打开卷句柄。

MSDN article on File Buffering 描述了对非缓存句柄的要求:

文件访问大小,包括 OVERLAPPED 结构中的可选文件偏移量(如果指定),必须是卷扇区大小的整数倍的字节数。例如,如果扇区大小为 512 字节,则应用程序可以请求读取和写入 512、1,024、1,536 或 2,048 字节,但不能请求 335、981 或 7,171 字节。

读写操作的文件访问缓冲区地址应该是物理扇区对齐的,这意味着在内存中的地址上对齐,该地址是卷的物理扇区大小的整数倍。根据磁盘的不同,可能不会强制执行此要求。

严格的代码应该检查相关文件系统的扇区大小,然后使用this approach 分配内存。但是,根据我的经验,扇区大小始终小于或等于分配粒度,因此您可以不使用 VirtualAlloc() 分配内存块。

【讨论】:

    【解决方案2】:

    缓冲区大小需要与硬盘扇区大小对齐

    WIN32_FIND_DATA atr = {0};
    DWORD BYTES_PER_SECTOR;
    char path[MAX_PATH];
    
    /* get path length current dir */
    const size_t len = GetCurrentDirectory(0, 0); 
    
    /* set path to path char array */
    GetCurrentDirectory(len, path);
    
    /* windows function to get disk details */
    GetDiskFreeSpace(NULL, NULL, &BYTES_PER_SECTOR, NULL, NULL); 
    
    /* find first file in dir */
    find = FindFirstFile(path, &atr);
    
    for(;find != INVALID_HANDLE_VALUE;){
    
    /* get the file size */
    DWORD filesize = atr.nFileSizeLow;
      if(atr.nFileSizeHigh > 0){
                         filesize = atr.nFileSizeHigh;
                         filesize = (filesize << 31);
                         filesize = atr.nFileSizeLow;
                         }
     /* sector size aligned file size */
     size_t buffer_size = ((BYTES_PER_SECTOR + ((filesize + BYTES_PER_SECTOR)-1)) & ~(BYTES_PER_SECTOR -1));
    
     /* create buffer */
     DWORD buffer[buffer_size];                                                       
    
     /* create a new file or open an existing file */
     handle =   CreateFile(&path[0], GENERIC_READ | GENERIC_WRITE, 0 , NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL))!=INVALID_HANDLE_VALUE)
    
     /* read the file in to buffer */
     ReadFile(handle, (void*)&buffer, buffer_size, &bytesread, NULL)
    
    if(FindNextFile(find, &atr)==0){ printf("last file processed, leaving\n");break;};
     } 
     CloseHandle(file);
     FindClose(find);
    

    【讨论】: