【问题标题】:FILE_FLAG_NO_BUFFERING with overlapped I/O - bytes read zero带有重叠 I/O 的 FILE_FLAG_NO_BUFFERING - 字节读取为零
【发布时间】:2013-07-22 05:00:49
【问题描述】:

我在使用带有重叠 I/O 的标志 FILE_FLAG_NO_BUFFERING 时观察到一种奇怪的行为。 我调用了一系列 ReadFile() 函数调用,稍后使用 GetOverlappedResult() 查询它们的状态。

我所说的奇怪行为是,即使文件句柄很好并且 ReadFile() 调用返回时没有任何错误错误(预期的 ERROR_IO_PENDING 除外),从 GetOverlappedResult() 调用返回的“字节读取”值是一些文件为零,每次我运行代码时 - 它是一组不同的文件。 如果我删除了 FILE_FLAG_NO_BUFFERING,一切都会开始正常工作,并且没有字节读取值为零。

这是我使用 FILE_FLAG_NO_BUFFERING 实现重叠 I/O 代码的方法。

long overlappedIO(std::vector<std::string> &filePathNameVectorRef)
{    
    long totalBytesRead = 0;
    DWORD bytesRead = 0;
    DWORD bytesToRead = 0;
    std::map<HANDLE, OVERLAPPED> handleMap;
    HANDLE handle = INVALID_HANDLE_VALUE;
    DWORD accessMode = GENERIC_READ;
    DWORD shareMode = 0;
    DWORD createDisposition = OPEN_EXISTING;
    DWORD flags = FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING;

    DWORD fileSize;
    LARGE_INTEGER li;
    char * buffer;
    BOOL success = false;

    for(unsigned int i=0; i<filePathNameVectorRef.size(); i++)
    {
        const char* filePathName = filePathNameVectorRef[i].c_str();

        handle = CreateFile(filePathName, accessMode, shareMode, NULL, createDisposition, flags, NULL);

        if(handle == INVALID_HANDLE_VALUE){
            fprintf(stdout, "\n Error occured: %d", GetLastError());
            fprintf(stdout," getting handle: %s",filePathName);
            continue;
        }
        GetFileSizeEx(handle, &li);
        fileSize = (DWORD)li.QuadPart;

        bytesToRead = (fileSize/g_bytesPerPhysicalSector)*g_bytesPerPhysicalSector;
        buffer = static_cast<char *>(VirtualAlloc(0, bytesToRead, MEM_COMMIT, PAGE_READWRITE));

        OVERLAPPED overlapped;
        ZeroMemory(&overlapped, sizeof(overlapped));
        OVERLAPPED * lpOverlapped = &overlapped;

        success = ReadFile(handle, buffer, bytesToRead, &bytesRead, lpOverlapped);

        if(!success && GetLastError() != ERROR_IO_PENDING){ 
            fprintf(stdout, "\n Error occured: %d", GetLastError());
            fprintf(stdout, "\n reading file %s",filePathName);
            CloseHandle(handle);
            continue;
        }
        else
            handleMap[handle] = overlapped;
    }

    // Status check and bytes Read value
    for(std::map<HANDLE, OVERLAPPED>::iterator iter = handleMap.begin(); iter != handleMap.end(); iter++)
    {
        HANDLE handle = iter->first;        
        OVERLAPPED * overlappedPtr = &(iter->second);

        success = GetOverlappedResult(handle, overlappedPtr, &bytesRead, TRUE);
        if(success)
        {
                /* bytesRead value in some cases is unexpectedly zero */
                /* no file is of size zero or lesser than 512 bytes(physical volume sector size) */
            totalBytesRead += bytesRead;
            CloseHandle(handle);
        }
    }

    return totalBytesRead;
}

如果没有 FILE_FLAG_NO_BUFFERING,totalBytesRead 的值为 57 MB。存在该标志时,totalBytesRead 值远低于 57 MB,并且每次运行从 2 MB 到 15 MB 的代码时都会不断变化。

【问题讨论】:

  • 您对 OVERLAPPED 结构的处理方法是错误的。您正在传递超出范围的堆栈变量的地址。更改映射以保存指向 OVERLAPPED 结构的指针,并将它们分配在堆上。此外,对于重叠 I/O,第一个 ReadFile() 调用的第四个参数应该为 NULL。
  • 它不会超出范围。但这肯定是错误的,每个 ReadFile() 都会使用同一个。那是行不通的。同样值得怀疑的是,这是否会真正改善任何事情,重叠 I/O 只有在您不等待它完成时才有意义。文件系统是否可以利用多个重叠是一个遥远的目标。

标签: c++ windows winapi file-io


【解决方案1】:

当文件大小小于 g_bytesPerPhysicalSector 时,您对 bytesToRead 的计算将产生 0 作为结果。因此,对于小文件,您请求 0 个字节。

【讨论】:

    猜你喜欢
    • 2015-04-23
    • 2020-03-11
    • 2023-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-04
    • 2021-12-04
    • 1970-01-01
    相关资源
    最近更新 更多