<=
Перед тем как начать, хоть уточнить:
Ожидается что у вас есть хоть какое то представление о "file of T".
Конечно, без того можно разобраться, но будет сложнее.
Объявление
"file of T":
begin
var f: file of T;
Assign(f, 'temp.bin');
end.
"BlockFileOf<T>":
uses BlockFileOfT;
begin
var f: BlockFileOf<T>;
f := new BlockFileOf<T>;//В отличии от file of T - BlockFileOf<T> надо всегда инициализировать
f.Assign('temp.bin');
end.
Последнее можно сократить:
uses BlockFileOfT;
begin
var f := new BlockFileOf<T>;
f.Assign('temp.bin');
end.
И ещё больше сократить:
uses BlockFileOfT;
begin
var f := new BlockFileOf<byte>('temp.bin');
end.
Основы записи/чтения
"file of T":
begin
var f: file of integer;
Rewrite(f, 'temp.bin');
f.Write(
1,2,3,4,5
);
f.Close;
Reset(f);
loop 5 do
f.Read.Print;
f.Close;
end.
"BlockFileOf<T>":
uses BlockFileOfT;
begin
var f := new BlockFileOf<integer>('temp.bin');
f.Rewrite;
f.Write(
1,2,3,4,5
);
f.Close;
f.Reset;
f.Read(5).Print;
f.Close;
end.
В случае с "BlockFileOf<T>" все 5 элементов читаются как 1 блок памяти.
В то время как "file of T" может прочитать только по 1 элементу.
Перечисление всех элементов в файле
"file of T":
begin
var f: file of integer;
Rewrite(f, 'temp.bin');
f.Write(
1,2,3,4,5
);
f.Close;
Reset(f);
f.ReadElements.Print
f.Close;
end.
"BlockFileOf<T>":
uses BlockFileOfT;
begin
var f := new BlockFileOf<integer>('temp.bin');
f.Rewrite;
f.Write(
1,2,3,4,5
);
f.Close;
f.Reset;
f.ToSeq.Print;
f.Close;
end.
"BlockFileOf<T>.ToSeq" работает так же как и "(file of T).ReadElements" (если не считать более продвинутой защиты от дурака):
Они оба читают файл по 1 элементу, и после каждого из них проверяют, не достигнут ли конец файла.
Но в "BlockFileOf<T>" есть альтернатива - "ToSeqBlocks".
Эта функция читает всё из файла блоками заданной (в байтах) длины. Если её не задать - будет по умолчанию, то есть 4КБ.
В нашем случае, "integer" занимает 4 байта в памяти, значит в каждом блоке по 4КБ поместится 1024 элемента типа "integer"
(Объём типа T можно узнать из свойства "BlockFileOf<T>.TSize", или с помощью sizeof(T) )
В случае с 5 элементами это едва ли даст преимущество, но если записывать и считывать сразу много элементов - считывание блоками будет на много быстрее:
uses BlockFileOfT;
begin
var f := new BlockFileOf<integer>('temp.bin');
f.Rewrite;
f.Write(
1,2,3,4,5
);
f.Close;
f.Reset;
var blocks := f.ToSeqBlocks;
var AsSeq := blocks.SelectMany(bl->bl);
AsSeq.Print;
f.Close;
end.
"AsSeq := blocks.SelectMany(bl->bl)" здесь делает так, что хоть всё считывается из файла блоками,
переменную "AsSeq" будет воспринимать как последовательность элементов, а не последовательность блоков.
И - я расписал вывод как 3 строчки чтоб было виднее. Можно и сократить:
f.Reset;
f.ToSeqBlocks.SelectMany(bl->bl).Print;
f.Close;
Основное преимущество: сохранение записей (record)
uses BlockFileOfT;
type
r1=record
b1:byte;
i:integer;
b2:byte;
constructor(b1:byte; i:integer; b2:byte);
begin
self.b1 := b1;
self.i := i;
self.b2 := b2;
end;
///Эта функция определяет, как данную запись выведет на экран
function ToString:string; override :=
$'r1(b1={b1}, i={i}, b2={b2})';
end;
begin
var f := new BlockFileOf<r1>('temp.bin');
f.Rewrite;
f.Write(
new r1(1,2,3)
);
f.Close;
f.Reset;
writeln(f.Read);
f.Close;
end.
Казалось бы, тот же самый код будет работать и для "file of T".
Но вся разница находится в реализации:
"file of T" в данном случае, при вызове "Read" сначала прочитал бы названия и типы полей "r1" из его типа (через "System.Runtime"),
а затем, по очереди, читал бы из файла значение того же типа, что и у поля ("byte", затем "integer" и снова "byte"),
сохраняя прочитаные значения в соответствующих полях результата.
А "BlockFileOf<T>" подходит к этому с другой стороны.
Когда вы первый раз инициализируете переменную типа "BlockFileOf<r1>" -
объём в памяти занимаемый переменными типа "r1" вычисляется и сохраняется во внутрее статичное поле
(Его можно получить через свойство "TSize")
И когда вызывается функция "Read" - "BlockFileOf<T>" читает из файла столько байт, сколько занимают переменные типа "r1",
А потом копирует содержимое полученного массива байт в результат.
То есть, "file of T" читает 3 блока, а "BlockFileOf<T>" только 1.
И когда объём данных одинаковый - количество блоков очень важный фактор.
Поэтому "BlockFileOf<T>" будет быстрее.
И размер 1 блока не ограничивается размером 1 переменной типа "r1".
"Read(10)", к примеру, прочитает 1 блоком то, что "file of T" читал бы как 30 блоков.
Ну и, конечно, всё то же самое касается и "Write", не только "Read".