如何使用ReadFileScatter

时间:2017-06-28 15:40:16

标签: c++ winapi asynchronous readfile

我今天一直试图在我的代码中使用ReadFileScatter(听起来就像我需要的那样),到目前为止没有太多运气。谷歌在互联网上出错的原因并没有给我太多的了解。

文档说明:

  

数组必须包含足够的元素来存储nNumberOfBytesToRead字节的数据,以及一个用于终止NULL的元素。例如,如果要读取40 KB并且页面大小为4 KB,则该数组必须包含11个元素,其中包含10个数据和1个用于NULL的元素。

     

每个缓冲区必须至少是系统内存页面的大小,并且必须在系统内存页面大小边界上对齐。系统将一个系统内存页面的数据读入每个缓冲区。

     

该函数按顺序将数据存储在缓冲区中。例如,它将数据存储到第一个缓冲区,然后存储到第二个缓冲区,依此类推,直到每个缓冲区都被填满,所有数据都被存储,或者没有更多的缓冲区。

到目前为止,我一直试图这样做。我使用VirtualAlloc分配了一堆字节(确保了页边界约束),在列表中添加了一个终结符NULL,确保磁盘上的数据位于系统边界(并且隐式地是磁盘扇区大小边界)并发出电话。

没有进一步的原因,这是C ++中的最小测试用例:

// Setup: c:\tmp\test.dat is a file with at least 12K of stuff. 
// I attempt to read page 2/3, e.g. offset [4096-4096+8192>

// TEST:
SYSTEM_INFO systemInfo;
GetSystemInfo(&systemInfo);
auto pageSize = systemInfo.dwPageSize;
std::cout << "Page size: "<< pageSize << std::endl;

// Allocate 2 pages that are aligned with one in the middle:
auto buffer = reinterpret_cast<char*>(VirtualAlloc(NULL, pageSize * 3, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE));

// Create read buffer:
std::vector<FILE_SEGMENT_ELEMENT> elements;
{
    FILE_SEGMENT_ELEMENT element1;
    element1.Buffer = buffer;
    elements.push_back(element1);
}
{
    FILE_SEGMENT_ELEMENT element2;
    element2.Buffer = buffer + pageSize * 2;
    elements.push_back(element2);
}
{
    FILE_SEGMENT_ELEMENT terminator;
    terminator.Buffer = NULL;
    elements.push_back(terminator);
}

// [..] Physical sector size is normally checked as well. In my case it's 512 bytes, 
// so I guess that's irrelevant here.
//
// Open file:
auto fileHandle = CreateFile(
    "c:\\tmp\\test.dat", 
    GENERIC_READ | GENERIC_WRITE, 
    FILE_SHARE_READ, 
    NULL, 
    OPEN_ALWAYS, 
    FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH, 
    NULL);

auto err = GetLastError();
if (err != ERROR_ALREADY_EXISTS && err != ERROR_SUCCESS)
{
    throw std::exception(); // FIXME.
}

OVERLAPPED overlapped;
memset(&overlapped, 0, sizeof(OVERLAPPED));

LARGE_INTEGER tmp;
tmp.QuadPart = 4096; // Read from disk page 1

overlapped.Offset = tmp.LowPart;
overlapped.OffsetHigh = tmp.HighPart;
overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

auto succes = ReadFileScatter(fileHandle, elements.data(), pageSize * 2, NULL, &overlapped);
err = GetLastError();

if (!succes && err != ERROR_IO_PENDING && err != ERROR_SUCCESS)
{
    throw std::exception(); // The call always ends up here with error 87: Invalid parameter
}

WaitForSingleObject(overlapped.hEvent, INFINITE);

std::cout << "Call succeeded!" << std::endl;

// FIXME: Proper exception handling.

// Clean up:
VirtualFree(buffer, pageSize * 3, MEM_DECOMMIT | MEM_RELEASE);
CloseHandle(overlapped.hEvent);
CloseHandle(fileHandle);

在代码中,注释// The call always ends up here with error 87: Invalid parameter会记录错误。但是,据我所知,我检查了他们在MSDN上描述的所有方框......所以......

我在这里做错了什么?

0 个答案:

没有答案