[英]Read lines from file async using 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
使用SetFilePointer
來遍歷行?
當您使用FILE_FLAG_OVERLAPPED
標志打開文件,然后將OVERLAPPED
結構與ReadFile()
使用時,請使用OVERLAPPED.Offset
和OVERLAPPED.OffsetHigh
字段來指定應從其開始讀取的字節偏移量。 此外,如果同時運行它們,則必須為每個ReadFile()
使用單獨的OVERLAPPED
實例。 文檔中明確指出:
如果使用FILE_FLAG_OVERLAPPED打開hFile,則lpOverlapped參數必須指向有效且唯一的 OVERLAPPED結構,否則該函數可能會錯誤地報告讀取操作已完成。
對於支持字節偏移量的hFile,如果使用此參數,則必須指定一個字節偏移量,從該位置開始從文件或設備讀取。 通過設置OVERLAPPED結構的Offset和OffsetHigh成員可以指定此偏移量 。 對於不支持字節偏移量的hFile,將忽略Offset和OffsetHigh。
由於行的長度相同,因此可以輕松計算第二行和第四行的偏移量,然后針對這些偏移量發出兩個異步ReadFile()
調用,然后根據需要等待這兩個操作完成。
附帶說明一下,除非您真的知道自己在做什么,否則您實際上不應該使用FILE_FLAG_NO_BUFFERING
:
對於使用
FILE_FLAG_NO_BUFFERING
標志使用CreateFile打開的文件成功進行操作有嚴格的要求 ,有關詳細信息,請參閱文件緩沖 。
嘗試類似這樣的方法:
#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;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.