Вход/Регистрация
Фундаментальные алгоритмы и структуры данных в Delphi
вернуться

Бакнелл Джулиан М.

Шрифт:

begin

Result := FZeroPosition + FHeaderRec^.hrHeaderLen + (aIndex * FRecordLen4);

end;

Приведенный метод создания служебного заголовка вызывается только в случае, когда поток пуст. Принцип его работы очень прост. Сначала служебный заголовок создается в памяти, а затем записывается в поток. Если длина записи больше, чем нормальный размер служебного заголовка, его размер увеличивает до размера записи. В служебном заголовке содержится семь полей: поле сигнатуры, которое может использоваться для контроля при считывании записи;

номер версии служебного заголовка (это позволит в будущем добавлять в заголовок новые поля и сохранять совместимость версий);

длина служебного заголовка;

длина записи;

емкость потока (т.е. количество записей как активных, так и удаленных, которые в данный момент находятся в потоке);

количество активных записей;

и, наконец, порядковый номер первой удаленной записи (здесь значение этого поля устанавливается равным cEndOfDetectedChain или -2).

Метод считывания служебного заголовка должен содержать определенную проверку, которая будет гарантировать, что данный заголовок является действительным. Для этого сначала выполняется проверка сигнатуры, затем проверка того, что количество активных записей меньше или равно емкости потока и имеет ли поток достаточный объем для объявленной емкости. Если все проверки проходят успешно, считается, что служебный блок содержит корректные данные, и поля класса обновляются значениями, считанными из потока.

Метод rsCalcRecordOffset просто вычисляет смещение записи, порядковый номер которой передан ему во входном параметре. При этом учитывается начальное положение потока и размер служебного заголовка.

Листинг 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);

  • Читать дальше
  • 1
  • ...
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: