Windows для профессионалов


Обработка больших файлов


Я обещал рассказать, как спроецировать на небольшое адресное просранство файл длиной 16 экзабайтов. Так вот, этого сделать нельзя Вам придется проецировать не весь файл, а сго представление, содержащее лишь некую часть данных Вы начнете с того, что спроецируете представление самого начала файла Закончив обработку дан ных в этом представлении, Вы отключите его и спроецируете представление следую щей части файла — и так до тсх пор, пока нс будет обработан весь файл Конечно, это делает работу с большими файлами, проецируемыми в память, не слишком удоб ной, но утешимся тем, чго длина большинства файлов достаточно мала

Рассмотрим сказанное на примере файла размером 8 Гб Ниже приведен текст подпрограммы, позволяющей в несколько этапов подсчитывать, сколько раз встреча ется нулевой байт в том или ином двоичном файле данных.

__int64 CountOs(void)
{

// начальные границы представлений всегда начинаются no адресам,
// кратным гранулярности выделения памяти
SYSTEM_INFO sinf;
GetSystemInfo(&sinf);

// открываем файл данных
HANOLE hFile = CreateFile( "С:\\HugeFile.Big , GENERIC_READ, FILE_SHARE_READ NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL SCAN, NULL);

// создаем объект проекция файла
HANDLE hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
DWORD dwFileSizeHigh;

__int64 qwFileSize = GetFileSize(hFile, &dwFileSizeHigh);
qwFileSize += (((__int64) dwFileSizeHigh) << 32);

// доступ к описателю объекта файл нам больше не нужен
CloseHandle(hFile);

__int64 qwFileOffset = 0;
qwNumOfOs = 0;

while (qwFileSize > 0)
{

// определяем, сколько байтов надо спроецировать
DWORD dwBytesInBlock = sinf.dwAllocationGranularity;

if (qwFileSize < sinf.dwAllocationGranularity)

dwBytesInBlock = (DWORD)qwFileSize;



PBYTE pbFile = (PBYTE)MapViewOfFile(hFileMapping, FILE_MAP_READ, (DWORD) (qwFileOffset >> 32), // начальный байт (DWORD) (qwFileOffset & 0xFFFFFFFF), // в файле dwBytesInBlock); // число проецируемых байтов

// подсчитываем количество нулевых байтов в этом блоке


for (DWORD dwByte = 0; dwByte < dwBytesInBlock; dwByte++)
{

if (pbFilfe[dwByte] == 0)

qwNumOfOs++;

}

// прекращаем проецирование представления, чтобы в адресном пространстве
// не образовалось несколько представлений одного файла

UnmapViewOfFiie(pbFile);

// переходим к следующей группе байтов в файле
qwFileOffset += dwBytesInBlock;
qwFileSize -= dwBytesInBlock;

}

CloseHandle(hFileMapping);

return(qwNumOfOs);

}

Этот алгоритм проецирует представления по 64 Кб (в соответствии с грануляр ностью выделения памяти) или менее Кроме того, функция MapViewOfFile требует, чтобы передаваемое ей смещение в файле тоже было кратно гранулярности выделе ния памяти. Подпрограмма проецирует на адресное пространство сначала одно пред ставление, подсчитывает в нем количество нулей, затем переходит к другому пред ставлению, и все повторяется. Спроецировав и просмотрев все 64-килобайтовые бло ки, подпрограмма закрывает объект "проекция файла".


Содержание раздела