Createfile2, ReadFile и WriteFile; почему ReadFile не читает то, что я написал в WriteFile?

Для тестирования и чтобы убедиться, что у меня все есть, чтобы я мог начать масштабирование позже, я пытаюсь создать дескриптор файла, записать заданный буфер байтов в этот дескриптор файла, а затем прочитать часть этого файла в новый тестовый буфер.

У меня есть код:

const size_t vSize = 0x10000;

std::vector<byte> buffer(vSize, 0);

for (int i = 0; i != vSize; ++i)
{
    buffer[i] = i & 0xff;
}

std::wstring path = ApplicationData::Current->LocalFolder->Path->Data();

std::wstring testFileName = path + std::wstring(L"\\TestVariablySized");

_CREATEFILE2_EXTENDED_PARAMETERS extend = { 0 };
extend.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS);
extend.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
extend.dwFileFlags = FILE_FLAG_NO_BUFFERING;
extend.dwSecurityQosFlags = SECURITY_ANONYMOUS;
extend.lpSecurityAttributes = nullptr;
extend.hTemplateFile = nullptr;

HANDLE hMappedFile = CreateFile2(
    testFileName.c_str(),
    GENERIC_READ | GENERIC_WRITE,
    0,
    OPEN_ALWAYS,
    &extend);

_OVERLAPPED positionalData;
positionalData.Offset = 0;
positionalData.OffsetHigh = 0;
positionalData.hEvent = 0;

WriteFile(
    hMappedFile,
    &buffer[0],
    vSize,
    NULL,
    positionalData);

std::vector<byte> testBuffer(128);

ReadFile(
    hMappedFile,
    (LPVOID)&testBuffer[0],
    128,
    NULL,
    &positionalData);

К сожалению, когда я устанавливаю точку останова после и проверяю, что на самом деле находится в testBuffer, я обнаруживаю, что там все нули. Я также пробовал все вышеперечисленное без positionalData (т.е. заменяя его на NULL в вызовах WriteFile/ReadFile), но это не меняет результат. Точно так же я пробовал это с NULL вместо расширенных параметров для CreateFile2, тот же результат.

В конечном итоге я захочу иметь возможность выбирать произвольное место в данном файле для чтения байтов, поэтому, если я делаю что-то странное с positionalData, сообщите мне об этом.

На данный момент я не знаю, связана ли проблема с CreateFile2, ReadFile, WriteFile или их комбинацией. Ваша помощь очень ценится!

edit: оказывается, что ReadFile() возвращает False, а последний код ошибки после этого — 0x57 (87) — ERROR_INVALID_PARAMETER. В настоящее время гуглю об этом, но в случае, если я не могу получить ответ, я все еще заинтересован в прочтении предложений. Для меня не сразу очевидно, что я сделал не так, но мое первое предположение состоит в том, что я каким-то образом допустил ошибку с positionalData.

последнее редактирование: удаление FILE_FLAG_NO_BUFFERING сделало работу в конце. Спасибо!


person MNagy    schedule 25.10.2016    source источник
comment
ReadFile() возвращает BOOL, указывающий на успех или ошибку. Проверьте, является ли оно FALSE, и если да, то вызовите GetLastError(), чтобы найти код ошибки.   -  person MrEricSir    schedule 25.10.2016
comment
Спасибо за совет. ReadFile() действительно возвращал false и выдавал мне код ошибки 0x57 (87). Погуглил об этом прямо сейчас.   -  person MNagy    schedule 25.10.2016
comment
Ошибка 87: ERROR_INVALID_PARAMETER. ReadFile() не работает, потому что вы не соблюдаете ограничения, наложенные FILE_FLAG_NO_BUFFERING флаг. Если вы избавитесь от этого флага, код, скорее всего, будет работать. В противном случае обновите код, чтобы правильно следовать правилам.   -  person Remy Lebeau    schedule 25.10.2016
comment
Вы правы, удаление FILE_FLAG_NO_BUFFERING заставило его работать.   -  person MNagy    schedule 25.10.2016


Ответы (1)


Когда вы передаете структуру OVERLAPPED в WriteFile()/ReadFile() при использовании синхронного дескриптора файла, функции будут записывать/считывать байты по смещению начального файла, заданному OVERLAPPED, а затем обновлять OVERLAPPED, чтобы он содержал новый смещение файла после байтов, которые были записаны/прочитаны. Вы передаете один и тот же OVERLAPPED и WriteFile(), и ReadFile(), но вы не перематываете смещение OVERLAPPED перед передачей его ReadFile(), поэтому ReadFile() не читает ранее записанные байты.

ULARGE_INTEGER ulOffset;
...

ulOffset.QuadPart = 0; // or whatever offset you need
positionalData.Offset = ulOffset.LowPart;
positionalData.OffsetHigh = ulOffset.HighPart;
WriteFile(hMappedFile, ..., &positionalData);

...

ulOffset.QuadPart = 0; // or whatever offset you need
positionalData.Offset = ulOffset.LowPart;
positionalData.OffsetHigh = ulOffset.HighPart;
ReadFile(hMappedFile, ..., &positionalData);

Когда вы передаете NULL вместо структуры OVERLAPPED, функции будут записывать/читать байты, начиная с текущего смещения файла, хранящегося в самом дескрипторе файла, а затем обновлять дескриптор, чтобы сохранить новое смещение файла после байтов, которые были записаны/прочитаны. Итак, если вы используете один и тот же дескриптор файла для записи и чтения, вам придется перемотать текущее смещение дескриптора файла, используя SetFilePointer() или SetFilePointerEx():

LARGE_INTEGER liOffset;
...

liOffset.QuadPart = 0; // or whatever offset you need
SetFilePointerEx(hMappedFile, liOffset, NULL, FILE_BEGIN);
WriteFile(hMappedFile, ..., NULL);

...

liOffset.QuadPart = 0; // or whatever offset you need
SetFilePointerEx(hMappedFile, liOffset, NULL, FILE_BEGIN);
ReadFile(hMappedFile, ..., NULL);

При этом вы открываете файл с флагом FILE_FLAG_NO_BUFFERING, который имеет очень жесткие ограничения на то, какие смещения файла, адреса буфера и размеры буфера могут быть во время файловых операций ввода-вывода. Прочтите документацию MSDN для получения подробной информации о конкретных правилах, которым вы должны следовать при использовании этого флага:

Буферизация файлов

person Remy Lebeau    schedule 25.10.2016
comment
Познавательно, спасибо. Однако проблема, с которой я сталкиваюсь, все еще сохраняется, даже после сброса positionalData.Offset до 0 после записи. - person MNagy; 25.10.2016
comment
Пометить ваш как правильный, так как это было по крайней мере половиной того, чтобы заставить его работать. Другая половина была последним комментарием, который вы оставили наверху. Изменить: теперь это полный ответ после вашего редактирования. - person MNagy; 25.10.2016