MapViewOfFile Example (Win32)

AceInfinity

Emeritus, Contributor
Joined
Feb 21, 2012
Posts
1,728
Location
Canada
Code:
[NO-PARSE]#ifdef _MSC_VER
# pragma warning(disable: 4996)
#endif

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <tchar.h>

#ifdef __MINGW32__
# define LONGLONG_FMT "%I64d"
#else
# define LONGLONG_FMT "%lld"
#endif

#define PAGE_SIZE 4096

int main(void)
{
    DWORD i;
    BOOL bSuccess = FALSE;

    HANDLE hFile = INVALID_HANDLE_VALUE;
    HANDLE hMapFile = NULL;

    LONGLONG lNullBytes = 0;
    DWORD dwOffset = 0;

    const TCHAR *lpcFilepath = TEXT("file_small.bin");
    const DWORD dwDataSize = PAGE_SIZE;

    /* Open file for read/write perissions with exclusive access for compatibility with
       PAGE_READWRITE page protection of the file mapping object to be created */
    hFile = CreateFile(lpcFilepath, GENERIC_READ | GENERIC_WRITE, 0, NULL,
                              OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE)
    {
        _ftprintf(stderr, TEXT("ERROR: Failed to open file '%s': 0x%lx\n"), lpcFilepath, GetLastError());
        goto cleanup;
    }

    /* Get filesize */
    LARGE_INTEGER liFilesize;
    if (!GetFileSizeEx(hFile, &liFilesize))
    {
        _ftprintf(stderr, TEXT("ERROR: Could not retrieve filesize: 0x%lx\n"), GetLastError());
        goto cleanup;
    }

    if (liFilesize.QuadPart == 0)
    {
        _ftprintf(stderr, TEXT("ERROR: Filesize is 0 bytes\n"));
        goto cleanup;
    }

    LONGLONG lFilesizeUnit = liFilesize.QuadPart;
    const TCHAR *lpcFilesizeSuffix = TEXT("bytes");
    if (lFilesizeUnit > 1024)
    {
        lpcFilesizeSuffix = TEXT("Kb");
        lFilesizeUnit /= 1024;
    }

    _tprintf(TEXT("Filesize: " LONGLONG_FMT " %s\n"), lFilesizeUnit, lpcFilesizeSuffix);

    /* Create a file mapping object for the file */
    hMapFile = CreateFileMapping(hFile, NULL, PAGE_READWRITE, liFilesize.u.HighPart, liFilesize.u.LowPart, NULL);
    if (hMapFile == NULL)
    {
        _ftprintf(stderr, TEXT("ERROR: Failed to create file mapping: 0x%lx\n"), GetLastError());
        goto cleanup;
    }

    /* Obtain system allocation granularity */
    SYSTEM_INFO sysInfo;
    GetNativeSystemInfo(&sysInfo);
    DWORD dwAllocGranularity = sysInfo.dwAllocationGranularity;
    _tprintf(TEXT("Allocation Granularity: %ldK\n"), dwAllocGranularity / 1024);

    do
    {
        /* File offset must be a multiple of system allocation granularity  */
        LARGE_INTEGER liFileMapViewOffset;
        liFileMapViewOffset.QuadPart = (dwOffset / dwAllocGranularity) * dwAllocGranularity;
        /* _tprintf(TEXT("File mapping view offset: " LONGLONG_FMT " bytes\n"), liFileMapViewOffset.QuadPart); */

        /* Calculate the size of the file mapping view */
        SIZE_T dwFileMapViewSize = (dwOffset % dwAllocGranularity) + dwDataSize;
        if (dwFileMapViewSize > (liFilesize.QuadPart - liFileMapViewOffset.QuadPart))
        {
            dwFileMapViewSize = (SIZE_T)(liFilesize.QuadPart - liFileMapViewOffset.QuadPart);
        }
        /* _tprintf(TEXT("File mapping view size: %ld bytes\n"), dwFileMapViewSize); */

        /* The bytes we want to read aren't always at the beginning of the mapped view */
        LONGLONG lViewOffset;
        lViewOffset = dwOffset - liFileMapViewOffset.QuadPart;
        /* _tprintf(TEXT("Data offset from view: " LONGLONG_FMT " bytes\n"), lViewOffset); */

        /* Map view of file and obtain pointer to base address of the region mapped in memory */
        LPVOID lpMapAddress = MapViewOfFile(hMapFile,
                                            FILE_MAP_READ,
                                            liFileMapViewOffset.u.HighPart,
                                            liFileMapViewOffset.u.LowPart,
                                            dwFileMapViewSize);

        if (lpMapAddress == NULL)
        {
            _ftprintf(stderr, TEXT("ERROR: MapViewOfFile failed: 0x%lx\n"), GetLastError());
            goto cleanup;
        }

        /* Calculate the offset pointer to data */
        PBYTE pBytes = (PBYTE)lpMapAddress + lViewOffset;
        LONGLONG lBytesTotal = liFilesize.QuadPart - liFileMapViewOffset.QuadPart;
        for (i = 0; i < lBytesTotal; ++i)
        {
            /*_tprintf(TEXT("%02X "), *(pBytes + i));*/
            if (!*(pBytes + i)) ++lNullBytes;
        }

        /* _tprintf(TEXT("\n")); */

        /* Unmap view of file */
        if (!UnmapViewOfFile(lpMapAddress))
        {
            _ftprintf(stderr, TEXT("ERROR: UnmapViewOfFile failed: 0x%lx\n"), GetLastError());
        }

        dwOffset += dwDataSize;
    }
    while (dwOffset < liFilesize.QuadPart);

    bSuccess = TRUE;

cleanup:

    /* Close file mapping object HANDLE */
    if (hMapFile != NULL)
    {
        bSuccess &= CloseHandle(hMapFile);
        if (!bSuccess)
        {
            _ftprintf(stderr, TEXT("ERROR: Failed to close HANDLE to file mapping object: 0x%lx\n"), GetLastError());
        }
    }

    /* Close file HANDLE */
    if (hFile != INVALID_HANDLE_VALUE)
    {
        bSuccess &= CloseHandle(hFile);
        if (!bSuccess)
        {
            _ftprintf(stderr, TEXT("ERROR: Failed to close HANDLE to file: 0x%lx\n"), GetLastError());
        }
    }

    if (bSuccess)
    {
        _tprintf(TEXT("Null byte count: " LONGLONG_FMT "\n"), lNullBytes);
    }

    _tprintf(TEXT("DONE!\n"));
    return bSuccess;
}[/NO-PARSE]

Here's some code I wrote a couple days ago to demonstrate efficiently reading files on Windows by mapping views to the file into memory from a mapping object.

It's pretty basic -- I can read a ~2.5 Gb file in about 5 seconds. Performing other things during the read is obviously going to increase that timeframe a little.

5LN3hhR.png


^ For this test I just took an ISO/Image for Windows 7 installation that I had on a USB. It reads through the file and counts null-bytes.

:thumbsup2:
 

Has Sysnative Forums helped you? Please consider donating to help us support the site!

Back
Top