Работа с массивами большой размерности в Delphi

Часто приходиться иметь дело с массивами, длина которых не поддерживается стандартным array of . Мне приходилось иметь дело с массивом данных содержащих более тридцами миллионов записей, каждая из которых была record агрегирующий  в себе 7 простых типов данных. При этом вы хотите обрадовать массив не простых типов данных Integer  или Double, а массив данных, которые вы объявили при помощи конструкций TMyRecord = Record .. end; или TMyClass = class .. end;.. Ваше Желание может быть объяснено простым желанием работать с удобной структурой данных, а не выделять множество массивов простых типов данных и потом имеь куцу проблем с областью видимости и передачи их как формальных параметров в функции и процедуры. При их размещении в памяти возникает ошибка

—————————

Debugger Exception Notification

—————————

raised exception class ERangeError with message ‘Range check error’.

—————————

Break   Continue   Help 

Или же

—————————

Debugger Exception Notification

—————————

raised exception class EOutOfMemory with message ‘Out of memory’.

—————————

Break   Continue   Help  

В первом случае в принципе не возможно задать массив такой длины, а во втором Объем памяти ,который запрашивает программа может превышать доступные на даны момент ресурсы компьютера.

Для решения проблемы воспользуемся функцией

function GetMem ( var StoragePointer : Pointer; StorageSize : Integer ) ;

которая описана в модуле (Юните, Unit) System;

Официальные источники дают следующие описание данной процедуры:

Процедура GetMem пытается получить указанные в StorageSize байт памяти, сохраняя указатель на память в StoragePointer. Если при распределении произошли сбои, то вызывается исключение EOutOfMemory. Память не всегда инициализируется.

Таким образом, для того, что бы воспользоваться этой функцией необходимо знать количество элементов (объектов), которое мы хотим выделить и количество байтов (размер каждого элемента). При этом StoragePointer должен быть указателем а StorageSize содержать длину оттельного объекта типа TMyRecord. При объявлении  TMyRecord  обязательно объявляйте его packed record. Например,

TMyRecord = packed Record .. end;

Директива packed поможет менеджеру памяти наиболее эффективно расположить в памяти каждую запись. Так же воздержитесь от использования в record использования данных не фиксированной длины, например, String вместо него используйте String[255] или любой другой нужной вам длины.

Длину отдельного объекта можно определить при помощи функции SizeOf.

Официальные источники дают следующие описание данной процедуры:

Функция SizeOf возвращает занимаемый размер (в байтах) переменной (Variable) или типа (Type).

То есть для того что бы узнать длину класса TMyRecord необходимо вызвать SizeOf(TMyRecord), при этом следует помнить, что SizeOf(TMyRecord) один раз вычисляет длину класса в байтах и при повторном вызове не будет повторно пересчитывать его длину, так что вызовы SizeOf(TMyRecord)  не могут серьезно повлиять на время выполнения программы.

Так что перед тем как начать заполнять данными область памяти необходимо подсчитать количество элементов, которое вам понадобиться. Даже если для этого понадобиться дважды прочитать текстовый файл.

var

F: TextFile ;

lValue: PMyRecord;

p: pointer;

lRowsCount: Integer;

begin

try

Result:= True;

AssignFile(F, APath);

lRowsCount:= 1;

Reset(F);

while not Eof(F) do

begin

Readln(F,str);

inc(lRowsCount);

end;

lRowsCount:= lRowsCount;

GetMem(p, lRowsCount*SizeOf(TMyRecord));

Reset(F);

APointer:= p;

lValue:= p;

while not Eof(F) do

begin

// считываем даные в массив

str:=”;

Readln(F, lValue^.EdgeGroupID, lValue^.Day, str);

lValue:= pointer(integer(lValue) + SizeOf(TJame));

end;

finally

CloseFile(F);

end;

end;

на соответствующий типа записи. Например, PMyRecord = ^TMyRecord,

Share

Tags: ,

11 Responses to “Работа с массивами большой размерности в Delphi”

  1. Игорь Меньшиков пишет:

    Занимательно и полезно, а будет еще что-то из этой же серии?

  2. Коля пишет:

    Да уж. Думаю многие будут не согласны..

  3. Адам пишет:

    Всем привет! Я здесь новенький. Примите в вашу компанию? :)

  4. Роман Морозов пишет:

    Свобода слова на блоге – это всегда хорошо! Главное, чтобы общественности было что Вам сказать :)

  5. Бог пишет:

    Хм… Пока это у нас не сильно развито, так что придётся подождать.

  6. Полет пишет:

    Спасибочки, что просветили. Никогда бы не подумал :)

  7. Богдан пишет:

    Премного благодарен. Прочитал с огромным интересом, и вообще полезный у Вас блог

  8. ankostey.ru пишет:

    Уважаемые, а нельзя оставлять комментарии по теме, а не разную глупость типа Спасибо за статью и т.д.

  9. Lalaine пишет:

    That saves me. Thkans for being so sensible!

  10. Аноним пишет:

    Решил вам немного помочь и послал этот пост в социальные закладки

Leave a Reply