Использование отображения памяти для больших файлов в Delphi
Я редко использую сопоставление памяти для больших файлов. Мне довелось столкнуться с таким требованием, поэтому я записал процесс, чтобы дать вам представление. Поскольку приложение не сложное, могут быть вещи, которые нельзя учитывать.
Для некоторых небольших файлов для решения проблемы можно использовать обычные файловые потоки. Однако для очень больших файлов, таких как 2G или более, файловые потоки не будут работать, поэтому вам необходимо даже использовать методы API, связанные с отображением памяти. если это отображение памяти, то весь размер файла также не может быть отображен сразу, поэтому отображение должно выполняться частями, обрабатывая небольшую часть за раз.
Давайте сначала рассмотрим некоторые функции
CreateFile: открыть файл
GetFileSize: получить размер файла.
CreateFileMapping: Создание сопоставления.
MapViewOfFile: файл сопоставления
Если посмотреть на MapViewOfFile, то его последние два параметра должны быть целым числом, кратным степени детализации страницы. Обычно степень детализации страницы составляет 64 КБ (65536 байт). Однако в нашей реальной работе это обычно не так. Возможна любая позиция, любая Любая длина, поэтому необходимо выполнить некоторую обработку.
Задача этого примера — последовательно прочитать значения длины из списка длин (FInfoList), а затем последовательно прочитать данные указанной длины из другого большого файла (FSourceFileName). Если это небольшой файл, это проще. для обработки Просто прочитайте поток файлов один раз, а затем прочитайте его последовательно. Для больших файлов нам нужно постоянно менять положение отображения, чтобы получить нужные данные.
В этом примере показано, что степень детализации страницы сначала получается с помощью GetSystemInfo, а затем 10-кратная степень детализации страницы используется в качестве отображаемого блока данных. В цикле for будет оцениваться, соответствует ли длина чтения (totallen) плюс длина для чтения. находятся в течение этого времени В пределах диапазона сопоставления (10-кратная степень детализации страницы), если он есть, продолжить чтение. Если он превышен, оставшиеся данные должны быть записаны, а затем следующий блок памяти должен быть перераспределен, а записанные оставшиеся данные должны быть объединены. в новое чтение. Полученные данные немного запутаны (возможно, моя идея слишком запутана),
Код указан ниже.
процедура TGetDataThread.DoGetData; var FFile_Handle: FFile_Map:THandle; p: PChar; я, интервал: Integer; смещение: = 0; tstream: = TMemoryStream.Create; список TMemoryStream.Create: = TStringList.Create; //Получаем системную информацию GetSystemInfo(sysinfo); //Размер блока детализации выделения страниц := sysinfo.dwAllocationGranularity; //Открываем файл FFile_Handle := CreateFile(PChar(FSourceFileName),GENERIC_READ,FILE_SHARE_READ,nil,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0); FFile_Handle = INVALID_HANDLE_VALUE then Exit; //Получаем размер файла:= GetFileSize(FFile_Handle,nil); //Создаем сопоставление FFile_Map := CreateFileMapping(FFile_Handle,nil,PAGE_READONLY,0,0,nil); если FFile_Map = 0, то Exit; //Здесь мы сопоставили 10-кратный размер блока в один блок данных. Если размер файла меньше 10-кратного размера блока, вся длина файла будет сопоставлена напрямую, если размер блока div файла > 10, то readlen := 10*blocksize else readlen := размер файла для i := от 0 до FInfoList.Count - 1 do start list.Delimiter := ':'; list.DelimitedText := FInfoList.Strings[i]; //Получить длину, я провел анализ здесь, потому что информация, которую я сохранил, имеет тип a:b:c, поэтому len разделяется ::= StrToInt(list.Strings[1]); .Strings[2]); если (i = 0) или (totallen+len >=readlen), то начать //Если длина чтения плюс длина чтения более чем в 10 раз превышает размер блока, то нам нужно сохранить содержимое в конце предыдущего сопоставления, чтобы объединить его с новым содержимым сопоставления, если i > 0, то начать offset := offset + readlen ; //Запись во временный поток tstream.Write(p^,readlen-totallen); tstream.Position := end; //Если длины непрочитанных данных недостаточно для одного выделения; детализацию, затем напрямую сопоставьте оставшуюся длину, если смещение размера файла < размер блока, затем readlen := размер файла-offset; //Отображение, p — указатель на область отображения //Обратите внимание, что третий параметр здесь всегда равен 0. Это значение должно быть установлено в соответствии с реальной ситуацией p:= PChar(MapViewOfFile( FFile_Map,FILE_MAP_READ, 0,offset,readlen)); end; //Если во временном потоке есть данные, их необходимо объединить, если tstream.Size > 0, то начать //Копируем временные данные потока в поток.CopyFrom(tstream,tstream.Size); //Затем записываем новые данные в конце и объединяем для завершения потока.Write(p^,len-tstream.Size); //Totallen := len); - tstream.Size; //Перемещаем указатель так, чтобы он указывал на начало следующих данных Inc(p,len-tstream.Size); tstream.Clear; end else Beginstream.Write(p^,len); тоталлен := тоталлен + len; Inc(p,len); end;stream.Position := 0; //Сохраняем поток в файлstream.SaveToFile(IntToStr(i)+'.txt'); Бесплатно; tstream.Free; CloseHandle(FFile_Handle); CloseHandle(FFile_Map); конец;
Если у вас есть какие-либо вопросы, оставьте сообщение или зайдите в сообщество этого сайта, чтобы пообщаться и обсудить. Надеюсь, это поможет всем. Спасибо за вашу поддержку этого сайта!