Чтение онлайн

на главную

Жанры

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

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

Шрифт:

end;

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

with FHeaderRec^ do

begin

hrSignature := cRSSignature;

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

hrRecordLen := aRecordLen;

hrCapacity := 0;

hrCount := 0;

hr1stDelRec := cEndOfDeletedChain;

end;

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

rsSeekStream(FZeroPosition);

rsWriteStream(FHeaderRec^, FHeaderRec^.hrHeaderLen);

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

FRecordLen := aRecordLen;

end;

procedure TtdRecordStream.rsReadHeaderRec;

var

StreamSize : longint;

TempHeaderRec : TtdRSHeaderRec;

begin

{если

размер потока меньше размера служебного заголовка, это неверный поток}

StreamSize := FStream.Size - FZeroPosition;

if (StreamSize < sizeof(TtdRSHeaderRec)) then

rsError(tdeRSNoHeaderRec, 'rsReadHeaderRec', 0);

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

rsSeekStream(FZeroPosition);

rsReadStream(TempHeaderRec, sizeof(TtdRSHeaderRec));

{первая санитарная проверка: сигнатура и счетчик/емкость}

with TempHeaderRec do

begin

if (hrSignatureocRSSignature) or (hrCount > hrCapacity) then

rsError(tdeRSBadHeaderRec, 'rsReadHeaderRec', 0);

end;

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

FHeaderRec := AllocMem(TempHeaderRec.hrHeaderLen);

Move(TempHeaderRec, FHeaderRec^, TempHeaderRec.hrHeaderLen);

{вторая санитарная проверка: проверка данных записи}

with FHeaderRec^ do

begin

FRecordLen4 := hrRecordLen + 4;

{for rsCalcRecordOffset}

if (StreamSize <> rsCalcRecordOffset(hrCapacity)) then

rsError(tdeRSBadHeaderRec, 'rsReadHeaderRec', 0);

{установить значения полей класса}

FCount :=hrCount;

FCapacity := hrCapacity;

FRecordLen := hrRecordLen;

end;

end;

function TtdRecordStream.rsCalcRecordOffset(aIndex : longint): longint;

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);

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

На границе империй. Том 6

INDIGO
6. Фортуна дама переменчивая
Фантастика:
боевая фантастика
космическая фантастика
попаданцы
5.31
рейтинг книги
На границе империй. Том 6

Курсант: Назад в СССР 4

Дамиров Рафаэль
4. Курсант
Фантастика:
попаданцы
альтернативная история
7.76
рейтинг книги
Курсант: Назад в СССР 4

С Новым Гадом

Юнина Наталья
Любовные романы:
современные любовные романы
эро литература
7.14
рейтинг книги
С Новым Гадом

Наследник

Кулаков Алексей Иванович
1. Рюрикова кровь
Фантастика:
научная фантастика
попаданцы
альтернативная история
8.69
рейтинг книги
Наследник

Приручитель женщин-монстров. Том 6

Дорничев Дмитрий
6. Покемоны? Какие покемоны?
Фантастика:
юмористическое фэнтези
аниме
5.00
рейтинг книги
Приручитель женщин-монстров. Том 6

Убивать чтобы жить 3

Бор Жорж
3. УЧЖ
Фантастика:
героическая фантастика
боевая фантастика
рпг
5.00
рейтинг книги
Убивать чтобы жить 3

Убивать, чтобы жить

Бор Жорж
1. УЧЖ
Фантастика:
героическая фантастика
боевая фантастика
рпг
5.00
рейтинг книги
Убивать, чтобы жить

Релокант. Вестник

Ascold Flow
2. Релокант в другой мир
Фантастика:
фэнтези
попаданцы
рпг
5.00
рейтинг книги
Релокант. Вестник

Неудержимый. Книга XIX

Боярский Андрей
19. Неудержимый
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Неудержимый. Книга XIX

Моя (не) на одну ночь. Бесконтрактная любовь

Тоцка Тала
4. Шикарные Аверины
Любовные романы:
современные любовные романы
7.70
рейтинг книги
Моя (не) на одну ночь. Бесконтрактная любовь

Папина дочка

Рам Янка
4. Самбисты
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Папина дочка

Первый пользователь. Книга 3

Сластин Артем
3. Первый пользователь
Фантастика:
боевая фантастика
рпг
5.00
рейтинг книги
Первый пользователь. Книга 3

Назад в СССР: 1985 Книга 2

Гаусс Максим
2. Спасти ЧАЭС
Фантастика:
попаданцы
альтернативная история
6.00
рейтинг книги
Назад в СССР: 1985 Книга 2

В теле пацана 4

Павлов Игорь Васильевич
4. Великое плато Вита
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
В теле пацана 4