Example: Sequential File Processing with Mapped Files
The atou program (Program 2-4) illustrates sequential file processing by converting ASCII files to Unicode, doubling the file length. This is an ideal application for memory-mapped files because the most natural way to convert the data is to process it one character at a time without being concerned with file I/O. Appendix C shows that the memory-mapped version can be considerably faster than the file access versions for NTFS files, so the complexity is worthwhile. The book's Web site contains additional performance studies; the highlights are summarized here.
- Memory-mapping performance improvements apply only to Windows NT and the NTFS.
- Compared with the best sequential file processing techniques, the performance improvements can be 3:1 or greater.
- The performance advantage disappears for larger files. In this example, as the input file size approaches about one-third of the physical memory size, normal sequential scanning is preferable. The mapping performance degrades at this point since the input file fills one-third of the memory and the output file, which is twice as long, fills the other two-thirds, forcing parts of the output files to be flushed to disk. Thus, on a 192MB system, mapping performance degenerates for input files longer than 60MB. Most file processing deals with smaller files and can take advantage of file mapping.
Program 2-4.
Program 5-3. Asc2UnMM: File Conversion with Memory Mapping
/* Chapter 5. Asc2UnMM.c: Memory-mapped implementation. */
#include "EvryThng.h"
BOOL Asc2Un (LPCTSTR fIn, LPCTSTR fOut, BOOL bFailIfExists)
{
HANDLE hIn, hOut, hInMap, hOutMap;
LPSTR pIn, pInFile;
LPWSTR pOut, pOutFile;
DWORD FsLow, dwOut;
/* Open and map both the input and output files. */
hIn = CreateFile (fIn, GENERIC_READ, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
hInMap = CreateFileMapping (hIn, NULL, PAGE_READONLY,
0, 0, NULL);
pInFile = MapViewOfFile (hInMap, FILE_MAP_READ, 0, 0, 0);
dwOut = bFailIfExists ? CREATE_NEW : CREATE_ALWAYS;
hOut = CreateFile (fOut, GENERIC_READ | GENERIC_WRITE,
0, NULL, dwOut, FILE_ATTRIBUTE_NORMAL, NULL);
FsLow = GetFileSize (hIn, NULL); /* Set the map size. */
hOutMap = CreateFileMapping (hOut, NULL, PAGE_READWRITE,
0, 2 * FsLow, NULL);
pOutFile = MapViewOfFile (hOutMap, FILE_MAP_WRITE, 0, 0,
(SIZE_T)(2 * FsLow));
/* Convert the mapped file data from ASCII to Unicode. */
pIn = pInFile;
pOut = pOutFile;
while (pIn < pInFile + FsLow)
{
*pOut = (WCHAR) *pIn;
pIn++;
pOut++;
}
UnmapViewOfFile (pOutFile); UnmapViewOfFile (pInFile);
CloseHandle (hOutMap); CloseHandle (hInMap);
CloseHandle (hIn); CloseHandle (hOut);
return TRUE;
}