繁体   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