Листинг 2.22. Добавление новой записи в постоянный массив
function TtdRecordStream.Add(var aRecord): longint;
begin
{если цепочка удаленных записей пуста, в поток добавляется новая запись}
if (FHeaderRec^.hr1stDelRec = cEndOfDeletedChain) then begin
Result :=FCapacity;
inc(FCapacity);
inc(FHeaderRec^.hrCapacity);
end
{в противном случае используется первая удаленная запись, обновляется значение поля удаленной записи в служебном заголовке для указания на следующую удаленную запись}
else begin
Result := FHeaderRec^.hr1stDelRec;
rsSeekStream(rsCalcRecordOffset(FHeaderRec^.hr1stDelRec))/ rsReadStream(FHeaderRec^.hr1stDelRec, sizeof(longint));
end;
{определить смещение записи и сохранить новую запись}
rsSeekStream(rsCalcRecordOffset(Result));
PLongint(FRecord)^ := cActiveRecord;
Move(aRecord, FRecord^[sizeof(longint)], FRecordLen);
rsWritestream(FRecord^, FRecordLen4);
{количество записей увеличилось на единицу}
inc(FCount);
inc(FHeaderRec^.hrCount);
{обновить служебный заголовок}
rsSeekStream(FZeroPosition);
rsWriteStream(FHeaderRec^, sizeof(TtdRSHeaderRec));
end;
Если цепочка удаленных записей не пуста, определить первую удаленную запись (именно поверх нее будет сохраняться новая запись). Мы считываем флаг удаления для этой записи и обновляем поле первой удаленной записи служебного заголовка. Затем мы определяем положение начала удаленной записи, устанавливаем значение флага удаления равным cActiveRecord (-1) и сохраняем запись, переданную методу во входном параметре.
При считывании и сохранении записей необходимо учитывать, удалена ли требуемая запись. Записи идентифицируются по их порядковым номерам.
Листинг 2.23. Чтение и обновление записи в постоянном массиве
procedure TtdRecordStream.Read(aIndex : longint; var aRecord; var alsDeleted : boolean);
begin
{проверить, действителен ли порядковый номер записи}
if (aIndex < 0) or (aIndex >= Capacity) then
rsError(tdeRSOutOfBounds, 'Read', aIndex);
{определить смещение записи и считать ее}
rsSeekStream(rsCalcRecordOffset(aIndex));
rsReadStream(FRecord^, FRecordLen4);
if (PLongint(FRecord)^ = cActiveRecord) then begin
alsDeleted := falser-Move (FRecord^[sizeof(longint)], aRecord, FRecordLen);
end
else begin
alsDeleted := true;
FillChar(aRecord, FRecordLen, 0);
end;
end;
procedure TtdRecordStream.Write(aIndex : longint; var aRecord);
var
DeletedFlag : longint;
begin
{проверить, действителен ли порядковый номер записи}
if (aIndex < 0) or (aIndex >= Capacity) then
rsError(tdeIndexOutOfBounds, 'Write', aIndex);
{проверить, что запись не была удалена}
rsSeekStream(rsCalcRecordOffset(aIndex));
rsReadStream(DeletedFlag, sizeof(longint));
if (DeletedFlag <> cActiveRecord) then
rsError(tdeRSRecIsDeleted, 'Write', aIndex);
{сохранить запись}
rsWriteStream(aRecord, FRecordLen);
end;
Метод Read возвращает флаг, который показывает, была ли удалена запись. Если запись не удалена, буфер записи, переданный во входном параметре, заполняется записью, считанной из потока. Код просто в один прием считывает всю запись и ее флаг удаления и действует в соответствии со значением флага.
Метод Write, прежде всего, проверяет, была ли удалена требуемая запись. Если запись удалена, она недоступна для изменения, вследствие чего возникает исключение. В противном случае в поток помещается новое значение записи.
И последний метод, связанный с обработкой записей, - это метод Delete.
Листинг 2.24. Чтение и обновление записи в постоянном массиве
procedure TtdRecordStream.Delete(aIndex : longint);
var
DeletedFlag : longint;
begin
{проверить, действителен ли порядковый номер записи}
if (aIndex < 0) or (aIndex >= Capacity) then
rsError(tdeRSOutOfBounds, 'Delete', aIndex);
{проверить, что запись не была удалена}
rsSeekStream(rsCalcRecordOffset(aIndex));
rsReadStream(DeletedFlag, sizeof(longint));
if (DeletedFlag <> cActiveRecord) then
rsError(tdeRSAlreadyDeleted, 'Delete', aIndex);
{записать порядковый номер первой удаленной записи в первые 4 байта удаляемой записи}
rsSeekStream(rsCalcRecordOffset(aIndex));
rsWriteStream(FHeaderRec^.hr1stDelRec, sizeof(longint));
{обновить значение поля первой удаленной записи служебного заголовка, чтобы оно указывало на удаляемую запись}