52704.fb2 Фундаментальные алгоритмы и структуры данных в Delphi - читать онлайн бесплатно полную версию книги . Страница 20

Фундаментальные алгоритмы и структуры данных в Delphi - читать онлайн бесплатно полную версию книги . Страница 20

Листинг 2.19. Конструктор класса TtdRecordStream

constructor TtdRecordStream.Create(aStream : TStream;

aRecordLength : integer);

begin

inherited Create;

{сохранить поток и его текущую позицию}

FStream := aStream;

FZeroPosition := aStream.Position;

{если размер потока равен нулю, нужно создать служебный заголовок}

if (aStream.Size - FZeroPosition = 0) then

rsCreateHeaderRec(aRecordLength) {в противном случае проверить, содержится ли в потоке действительный служебный заголовок, считать его и установить значения его полей}

else

rsReadHeaderRec;

{выделить память под запись}

FRecordLen4 := FRecordLen + sizeof(longint);

GetMem(FRecord, FRecordLen4);

end;

Обратите внимание, что конструктор считывает текущее положение потока и записывает его в FZeroPosition. Текущее положение, которое, как правило, равно нулю, будет использовать для указания положения служебного заголовка для постоянного массива. Это означает, что перед вызовом конструктора Create программист может записать в поток свой служебный заголовок, и методы класса не будут его изменять. Тем не менее, класс предполагает, что оставшаяся часть потока, начиная с положения FZeroPosition, принадлежит классу и в нее допускается вносить изменения.

Конструктор вызывает либо метод rsCreateHeaderRec, который создает новый служебный заголовок для пустого потока (т.е. при необходимости создания нового массива), либо метод rsReadHeaderRec, который считывает текущий служебный заголовок (и, кроме того, проверяет его корректность).

И, наконец, конструктор Create выделяет из кучи память для записи (память выделяется с учетом размера флага удаления). Деструктор Destroy освобождает память, выделенную под запись.

Листинг 2.20. Деструктор класса TtdRecordStream

destructor TtdRecordStream.Destroy;

begin

if (FHeaderRec <> nil) then

FreeMem(FHeaderRec, FheaderRec^.hrHeaderLen);

if (FRecord <> nil) then

FreeMem(FRecord, FRecordLen4);

inherited Destroy;

end;

А теперь давайте рассмотрим два вспомогательных метода, которые соответственно создают новый или считывают существующий служебный заголовок.

Листинг 2.21. Создание и считывание служебного заголовка

procedure TtdRecordStream.rsCreateHeaderRec(aRecordLen : integer);

begin

{выделить память под служебный заголовок}

if ((aRecordLen + sizeof(longint)) < sizeof(TtdRSHeaderRec)) then begin

FHeaderRec := AllocMem(sizeof(TtdRSHeaderRec));

FHeaderRec^.hrHeaderLen := sizeof(TtdRSHeaderRec);

end

else begin

FHeaderRec := AllocMem( aRecordLen + sizeof(longint));

FHeaderRec^.hrHeaderLen := aRecordLen + sizeof(longint);

end;

{задать значения остальных стандартных полей}

with FHeaderRec^ do

begin

hrSignature := cRSSignature;

hrVersion := $00010000; {Major=1; Minor=0}

hrRecordLen := aRecordLen;

hrCapacity := 0;

hrCount := 0;