Чтение строк из файла асинхронно с помощью WINAPI ReadFile

Мне нужно прочитать несколько строк из файла одновременно, то есть асинхронно.
Строки в файле имеют одинаковый размер.

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

Я более привык к асинхронности / ожиданию c # и всем этим OVERLAPPED вещи немного сложны для понимания для меня.

Используя примеры MSDN, я добился этого, он просто читает данные из файла в виде одной строки (это даже асинхронное чтение?):

BOOL ReadFromFileAsync(PCTSTR path)
{
HANDLE hFile = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, NULL);

if (hFile == INVALID_HANDLE_VALUE)
{
_tprintf_s(TEXT("INVALID_HANDLE_VALUE\n"));
return FALSE;
}

BOOL bResult;
BYTE bReadBuf[2048];

OVERLAPPED oRead = { 0 };
oRead.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
bResult = ReadFile(hFile, bReadBuf, _countof(bReadBuf), NULL, &oRead);

if (!bResult && GetLastError() != ERROR_IO_PENDING)
{
_tprintf_s(TEXT("ERROR io pending"));
CloseHandle(hFile);
return FALSE;
}

// perform some stuff asynchronously
_tprintf_s(TEXT("HEY\n"));

HANDLE hEvents[2];
hEvents[0] = oRead.hEvent;
hEvents[1] = oRead.hEvent;
DWORD dwWaitRes = WaitForMultipleObjects(_countof(hEvents), hEvents, FALSE, INFINITE);

switch (dwWaitRes - WAIT_OBJECT_0)
{
case 0: // reading finished
_tprintf_s(TEXT("String that was read from file: "));

for (int i = 0; i < oRead.InternalHigh; ++i)
_tprintf_s(TEXT("%c"), bReadBuf[i]);

_tprintf_s(TEXT("\n"));
break;

default:
_tprintf_s(TEXT("Nooo"));
}

CloseHandle(hFile);

return TRUE;
}

Не могли бы вы помочь мне с асинхронным чтением двух строк из файла?

Должен ли я использовать SetFilePointer за что двигаться по линиям?

1

Решение

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

Если hFile открывается с FILE_FLAG_OVERLAPPED, параметр lpOverlapped должен указывать на действительный и уникальный OVERLAPPED структура, в противном случае функция может неправильно сообщить о завершении операции чтения.

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

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

На заметку, вы действительно не должны использовать FILE_FLAG_NO_BUFFERING если только ты не ДЕЙСТВИТЕЛЬНО знаю, что вы делаете:

Есть строгие требования для успешной работы с файлами, открытыми с помощью CreateFile с помощью FILE_FLAG_NO_BUFFERING флаг, подробности см. Буферизация файлов.

Попробуйте что-то более похожее на это:

#include <vector>

BOOL ReadFromFileAsync(PCTSTR path)
{
BOOL bResult = FALSE;

HANDLE hFile = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED /*| FILE_FLAG_NO_BUFFERING*/, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
_tprintf_s(TEXT("Error opening file: %s\n"), path);
return FALSE;
}

DWORD dwLineSize = ...; // size of each line, in bytes
std::vector<BYTE> bSecondLineBuf(dwLineSize);
std::vector<BYTE> bFourthLineBuf(dwLineSize);

OVERLAPPED oReadSecondLine = { 0 };
OVERLAPPED oReadFourthLine = { 0 };

oReadSecondLine.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!oReadSecondLine.hEvent)
{
_tprintf_s(TEXT("Error creating I/O event for reading second line\n"));
goto done;
}
oReadSecondLine.Offset = ...; // offset of second line

oReadFourthLine.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!oReadFourthLine.hEvent)
{
_tprintf_s(TEXT("Error creating I/O event for reading fourth line\n"));
goto done;
}
oReadFourthLine.Offset = ...; // offset of fourth line

if (!ReadFile(hFile, &bSecondLineBuf[0], dwLineSize, NULL, &oReadSecondLine))
{
if (GetLastError() != ERROR_IO_PENDING)
{
_tprintf_s(TEXT("Error starting I/O to read second line\n"));
goto done;
}
}

if (!ReadFile(hFile, &bFourthLineBuf[0], dwLineSize, NULL, &oReadFourthLine))
{
if (GetLastError() != ERROR_IO_PENDING)
{
_tprintf_s(TEXT("Error starting I/O to read fourth line\n"));
CancelIo(hFile);
goto done;
}
}

// perform some stuff asynchronously
_tprintf_s(TEXT("HEY\n"));

HANDLE hEvents[2];
hEvents[0] = oReadSecondLine.hEvent;
hEvents[1] = oReadFourthLine.hEvent;

DWORD dwWaitRes = WaitForMultipleObjects(_countof(hEvents), hEvents, TRUE, INFINITE);
if (dwWaitRes == WAIT_FAILED)
{
_tprintf_s(TEXT("Error waiting for I/O to finish\n"));
CancelIo(hFile);
goto done;
}

_tprintf_s(TEXT("Strings that were read from file: "));

for (int i = 0; i < oReadSecondLine.InternalHigh; ++i)
_tprintf_s(TEXT("%c"), (TCHAR) &bSecondLineBuf[i]);
_tprintf_s(TEXT("\n"));

for (int i = 0; i < oReadFourthLine.InternalHigh; ++i)
_tprintf_s(TEXT("%c"), (TCHAR) &bFourthLineBuf[i]);
_tprintf_s(TEXT("\n"));

done:
if (oReadSecondLine.hEvent) CloseHandle(oReadSecondLine.hEvent);
if (oReadFourthLine.hEvent) CloseHandle(oReadFourthLine.hEvent);
CloseHandle(hFile);

return bResult;
}

В качестве альтернативы:

#include <vector>

BOOL ReadFromFileAsync(PCTSTR path)
{
BOOL bResult = FALSE;

HANDLE hFile = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED /*| FILE_FLAG_NO_BUFFERING*/, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
_tprintf_s(TEXT("Error opening file: %s\n"), path);
return FALSE;
}

DWORD dwLineSize = ...; // size of each line, in bytes
std::vector<BYTE> bSecondLineBuf(dwLineSize);
std::vector<BYTE> bFourthLineBuf(dwLineSize);

OVERLAPPED oReadSecondLine = { 0 };
OVERLAPPED oReadFourthLine = { 0 };

oReadSecondLine.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!oReadSecondLine.hEvent)
{
_tprintf_s(TEXT("Error creating I/O event for reading second line\n"));
goto done;
}
oReadSecondLine.Offset = ...; // offset of second line

oReadFourthLine.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!oReadFourthLine.hEvent)
{
_tprintf_s(TEXT("Error creating I/O event for reading fourth line\n"));
goto done;
}
oReadFourthLine.Offset = ...; // offset of fourth line

if (!ReadFile(hFile, &bSecondLineBuf[0], dwLineSize, NULL, &oReadSecondLine))
{
if (GetLastError() != ERROR_IO_PENDING)
{
_tprintf_s(TEXT("Error starting I/O to read second line\n"));
goto done;
}
}

if (!ReadFile(hFile, &bFourthLineBuf[0], dwLineSize, NULL, &oReadFourthLine))
{
if (GetLastError() != ERROR_IO_PENDING)
{
_tprintf_s(TEXT("Error starting I/O to read fourth line\n"));
CancelIo(hFile);
goto done;
}
}

// perform some stuff asynchronously
_tprintf_s(TEXT("HEY\n"));

HANDLE hEvents[2];
hEvents[0] = oReadSecondLine.hEvent;
hEvents[1] = oReadFourthLine.hEvent;

OVERLAPPED* pOverlappeds[2];
pOverlappeds[0] = &oReadSecondLine;
pOverlappeds[1] = &oReadFourthLine;

BYTE* pBufs[2];
pBufs[0] = &bSecondLineBuf[0];
pBufs[1] = &bFourthLineBuf[0];

DWORD dwNumReads = _countof(hEvents);

do
{
DWORD dwWaitRes = WaitForMultipleObjects(dwNumReads, hEvents, FALSE, INFINITE);
if (dwWaitRes == WAIT_FAILED)
{
_tprintf_s(TEXT("Error waiting for I/O to finish\n"));
CancelIo(hFile);
goto done;
}

if ((dwWaitRes >= WAIT_OBJECT_0) && (dwWaitRes < (WAIT_OBJECT_0+dwNumReads)))
{
DWORD dwIndex = dwWaitRes - WAIT_OBJECT_0;

_tprintf_s(TEXT("String that was read from file: "));

for (int i = 0; i < pOverlappeds[dwIndex]->InternalHigh; ++i)
_tprintf_s(TEXT("%c"), (TCHAR) pBufs[dwIndex][i]);
_tprintf_s(TEXT("\n"));

--dwNumReads;
if (dwNumReads == 0)
break;

if (dwIndex == 0)
{
hEvents[0] = hEvents[1];
pOverlappeds[0] = pOverlappeds[1];
pBufs[0] = pBufs[1];
}
}
}
while (true);

done:
if (oReadSecondLine.hEvent) CloseHandle(oReadSecondLine.hEvent);
if (oReadFourthLine.hEvent) CloseHandle(oReadFourthLine.hEvent);
CloseHandle(hFile);

return bResult;
}
4

Другие решения


По вопросам рекламы ammmcru@yandex.ru
Adblock
detector