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

на главную

Жанры

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

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

Шрифт:

Есть еще один вопрос, который проще рассмотреть на примере кода. Было бы довольно глупо ограничить концепцию постоянных (устойчивых) массивов только до файлов на диске. Несмотря на то что в подавляющем большинстве случаев будут использоваться файлы, ничто не мешает нам организовать постоянный массив в памяти или на любом другом устройстве хранения данных. Было бы удобно иметь класс постоянного массива, который пользуется потоками. В Delphi предусмотрен богатый набор классов потоков, включая файловый поток. Таким образом, если мы

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

Ниже приведен код класса TtdRecordStream - класса, предназначенного для постоянного хранения в потоке массива записей.

Листинг 2.18. Класс TtdRecordStream для хранения постоянных массивов.

type

TtdRecordStream = class private

FStream : TStream;

FCount : longint;

FCapacity : longint;

FHeaderRec : PtdRSHeaderRec;

FName : TtdNameString;

FRecord : PByteArray;

FRecordLen : integer;

FRecordLen4 : integer;

FZeroPosition : longint;

protected

procedure rsSetCapacity(aCapacity : longint);

procedure rsError(aErrorCode : integer; const aMethodName : TtdNameString; aNumValue : longint);

function rsCalcRecordOffset(aIndex : longint): longint;

procedure rsCreateHeaderRec(aRecordLen : integer);

procedure rsReadHeaderRec;

procedure rsReadStream(var aBuffer; aBufLen : integer);

procedure rsWriteStream(var aBuffer; aBufLen : integer);

procedure rsSeekStream(aOffset : longint);

public

constructor Create(aStream : TStream; aRecordLength : integer);

destructor Destroy; override;

procedure Flush; virtual;

function Add(var aRecord): longint;

procedure Clear;

procedure Delete(aIndex : longint);

procedure Read(aIndex : longint; var aRecord; var alsDeleted : boolean);

procedure Write(aIndex : longint; var aRecord);

property Capacity : longint read FCapacity write rsSetCapacity;

property Count : longint read FCount;

property RecordLength : integer read FRecordLen;

property Name : TtdNameString read FName write FName;

end;

К сожалению, для такого типа постоянных массивов очень сложно перегрузить операцию [], поэтому в классе TtdRecordStream свойство Items не используется. Вместо него введены простые методы Read и Write.

Конструктор Create может вызываться в двух режимах: для постоянного массива в потоке или не в потоке. Режим определяется самим конструктором и в случае, если используется новый поток, создается служебный блок.

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

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

На границе империй. Том 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