Rakesh Agarwal
Rakesh Agarwal

Reputation: 3059

FILE_FLAG_NO_BUFFERING with overlapped I/O - bytes read zero

I observe a weird behavior while using the flag FILE_FLAG_NO_BUFFERING with overlapped I/O. I invoke a series of ReadFile() function calls and query their statuses later using GetOverlappedResult().

The weird behavior that I am speaking of is that even though file handles were good and ReadFile() calls returned without any bad error(except ERROR_IO_PENDING which is expected), the 'bytes read' value returned from GetOverlappedResult() call is zero for some of the files, and each time I run the code - it is a different set of files. If I remove the FILE_FLAG_NO_BUFFERING, things start working properly and no bytes read value is zero.

Here is how I have implemented overlapped I/O code with FILE_FLAG_NO_BUFFERING.

long overlappedIO(std::vector<std::string> &filePathNameVectorRef)
{    
    long totalBytesRead = 0;
    DWORD bytesRead = 0;
    DWORD bytesToRead = 0;
    std::map<HANDLE, OVERLAPPED> handleMap;
    HANDLE handle = INVALID_HANDLE_VALUE;
    DWORD accessMode = GENERIC_READ;
    DWORD shareMode = 0;
    DWORD createDisposition = OPEN_EXISTING;
    DWORD flags = FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING;

    DWORD fileSize;
    LARGE_INTEGER li;
    char * buffer;
    BOOL success = false;

    for(unsigned int i=0; i<filePathNameVectorRef.size(); i++)
    {
        const char* filePathName = filePathNameVectorRef[i].c_str();

        handle = CreateFile(filePathName, accessMode, shareMode, NULL, createDisposition, flags, NULL);

        if(handle == INVALID_HANDLE_VALUE){
            fprintf(stdout, "\n Error occured: %d", GetLastError());
            fprintf(stdout," getting handle: %s",filePathName);
            continue;
        }
        GetFileSizeEx(handle, &li);
        fileSize = (DWORD)li.QuadPart;

        bytesToRead = (fileSize/g_bytesPerPhysicalSector)*g_bytesPerPhysicalSector;
        buffer = static_cast<char *>(VirtualAlloc(0, bytesToRead, MEM_COMMIT, PAGE_READWRITE));

        OVERLAPPED overlapped;
        ZeroMemory(&overlapped, sizeof(overlapped));
        OVERLAPPED * lpOverlapped = &overlapped;

        success = ReadFile(handle, buffer, bytesToRead, &bytesRead, lpOverlapped);

        if(!success && GetLastError() != ERROR_IO_PENDING){ 
            fprintf(stdout, "\n Error occured: %d", GetLastError());
            fprintf(stdout, "\n reading file %s",filePathName);
            CloseHandle(handle);
            continue;
        }
        else
            handleMap[handle] = overlapped;
    }

    // Status check and bytes Read value
    for(std::map<HANDLE, OVERLAPPED>::iterator iter = handleMap.begin(); iter != handleMap.end(); iter++)
    {
        HANDLE handle = iter->first;        
        OVERLAPPED * overlappedPtr = &(iter->second);

        success = GetOverlappedResult(handle, overlappedPtr, &bytesRead, TRUE);
        if(success)
        {
                /* bytesRead value in some cases is unexpectedly zero */
                /* no file is of size zero or lesser than 512 bytes(physical volume sector size) */
            totalBytesRead += bytesRead;
            CloseHandle(handle);
        }
    }

    return totalBytesRead;
}

With FILE_FLAG_NO_BUFFERING absent, totalBytesRead value is 57 MB. With the flag present, totalBytesRead value is much lower than 57 MB and keeps changing each time I run the code ranging from 2 MB to 15 MB.

Upvotes: 2

Views: 2049

Answers (1)

ScottMcP-MVP
ScottMcP-MVP

Reputation: 10415

Your calculation of bytesToRead will produce 0 as a result when the file size is less than g_bytesPerPhysicalSector. So for small files you are requesting 0 bytes.

Upvotes: 1

Related Questions