简体   繁体   English

使用WINAPI ReadFile从文件异步读取行

[英]Read lines from file async using WINAPI ReadFile

I need to read several lines from file simultaneously, ie asynchronously. 我需要同时(即异步)从文件中读取几行。 Lines in file are of the same size. 文件中的行大小相同。

For instance, I need to read the second and the fourth lines of file to separate variables or to an array. 例如,我需要读取文件的第二行和第四行以分隔变量或数组。

I'm more used to c#'s async/await and all these OVERLAPPED things are a bit difficult for understanding to me. 我更习惯于c#的异步/等待,所有这些OVERLAPPED东西对我来说都有点难以理解。

Using msdn examples, I achieved this, it just reads the data from the file as a one string (is that even asynchronous reading?): 使用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;
}

Could you help me with reading two lines from file asynchronously? 您能帮我从文件中异步读取两行吗?

Should I use SetFilePointer for that to move through the lines? 我是否应该SetFilePointer使用SetFilePointer来遍历行?

When you open a file with the FILE_FLAG_OVERLAPPED flag and then use an OVERLAPPED structure with ReadFile() , use the OVERLAPPED.Offset and OVERLAPPED.OffsetHigh fields to specify the byte offset where reading should start from. 当您使用FILE_FLAG_OVERLAPPED标志打开文件,然后将OVERLAPPED结构与ReadFile()使用时,请使用OVERLAPPED.OffsetOVERLAPPED.OffsetHigh字段来指定应从其开始读取的字节偏移量。 Also, you must use a separate OVERLAPPED instance for each ReadFile() if you run them simultaneously. 此外,如果同时运行它们,则必须为每个ReadFile()使用单独的OVERLAPPED实例。 This is clearly stated in the documentation : 文档中明确指出:

If hFile is opened with FILE_FLAG_OVERLAPPED, the lpOverlapped parameter must point to a valid and unique OVERLAPPED structure, otherwise the function can incorrectly report that the read operation is complete. 如果使用FILE_FLAG_OVERLAPPED打开hFile,则lpOverlapped参数必须指向有效且唯一的 OVERLAPPED结构,否则该函数可能会错误地报告读取操作已完成。

For an hFile that supports byte offsets, if you use this parameter you must specify a byte offset at which to start reading from the file or device. 对于支持字节偏移量的hFile,如果使用此参数,则必须指定一个字节偏移量,从该位置开始从文件或设备读取。 This offset is specified by setting the Offset and OffsetHigh members of the OVERLAPPED structure . 通过设置OVERLAPPED结构的Offset和OffsetHigh成员可以指定此偏移量 For an hFile that does not support byte offsets, Offset and OffsetHigh are ignored. 对于不支持字节偏移量的hFile,将忽略Offset和OffsetHigh。

As your lines are the same length, you can easily calculate the offsets of the second and fourth lines and then issue two asynchronous ReadFile() calls for those offsets, and then wait for the two operations to complete as needed. 由于行的长度相同,因此可以轻松计算第二行和第四行的偏移量,然后针对这些偏移量发出两个异步ReadFile()调用,然后根据需要等待这两个操作完成。

On a side note, you really should not be using FILE_FLAG_NO_BUFFERING unless you REALLY know what you are doing: 附带说明一下,除非您真的知道自己在做什么,否则您实际上不应该使用FILE_FLAG_NO_BUFFERING

There are strict requirements for successfully working with files opened with CreateFile using the FILE_FLAG_NO_BUFFERING flag, for details see File Buffering . 对于使用FILE_FLAG_NO_BUFFERING标志使用CreateFile打开的文件成功进行操作有严格的要求 ,有关详细信息,请参阅文件缓冲

Try something more like this instead: 尝试类似这样的方法:

#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;
}

Alternatively: 或者:

#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