簡體   English   中英

使用WINAPI ReadFile從文件異步讀取行

[英]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.OffsetOVERLAPPED.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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM