This repository has been archived on 2024-12-25. You can view files and clone it, but cannot push or open issues or pull requests.
OldPascalProjects/BlockFileOfT/Дополнительно.pas
2024-03-10 20:32:51 +03:00

79 lines
4.0 KiB
ObjectPascal
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

uses BlockFileOfT;
uses System.Runtime.InteropServices; // для StructLayout у r3
type
r1 = record
b1, b2: byte;
constructor(b1, b2: byte);
begin
self.b1 := b1;
self.b2 := b2;
end;
///Переопределение того - как объекты типа r1 будет выписывать writeln
function ToString: string; override :=
$'r1({b1}, {b2})';
end;
r2 = record
b: byte;
i: int64;
end;
[StructLayout(LayoutKind.&Explicit, Size=9)]
r3 = record
[FieldOffset(0)] b: byte;
// Явно указываем что i будет хранится на следующем байте после b
// Так можно даже накладывать поля друг на друга
// Но поэтому также нужно относиться с осторожностью к такой возможности
// И помнить у какого типа какой размер, чтобы наложение полей не получилось там, где оно не требуется
[FieldOffset(1)] i: int64;
end;
begin
var f := new BlockFileOf<r1>('temp.bin');
f.Rewrite;
f.Write(new r1(1, 2));
f.Write(new r1(3, 4));
f.Write(new r1(5, 6));
f.Pos := 1;
var str := f.BaseStream;
var br := new System.IO.BinaryReader(str);
Writeln(br.ReadByte); // 3 - потому что прочитало 1 байт, когда файловый курсор стоял в начале элемента #1
// А вот так делать не следует. Сейчас курсор находится в середине второго элемента
// Обычно это вызовет неопределённое поведение и заполнит поля полученной записи мусором
// Но этот случай простой, поэтому точно известно что прочитает половину второй и половину третьей записи и выведет (4,5)
Writeln(f.Read);
// Если вы НЕ пытаетесь специально читать мимо элементов - стоит устанавливать позицию в файле (f.Pos := ...) после прямой работы с BaseStream
f.Pos := 0;
f.PosByte += 1; // сдвигаем курсор на один байт (вся запись f.TSize байт, что, в данном случае, 2)
// br и f всё ещё работают над тем же потоком, потому что мы не закрывали файл
// А файловый курсор хранится как раз в потоке
// Поэтому br можно всё ещё использовать и он будет синхронизирован с f.PosByte
Writeln(br.ReadByte); // 2, потому что второй байт первой записи
f.Close;
var f2 := new BlockFileOf<r2>;
// f2.TSize это то же самое, что sizeof(r2)
// У меня 16, хотя sizeof(byte)=1 + sizeof(int64)=8, то есть должно быть 9?
// Это потому, что на многих процессорах добавляет отступы (так легче читать/записывать значения) в некоторые записи, так что будьте осторожны
// Это также хорошая причина не пользоваться бездумно BaseStream - потому что на разных компьютерах один и тот же код может работать по-разному
Writeln(f2.TSize);
var f3 := new BlockFileOf<r3>;
// А вот теперь размер 9, потому что мы явно указали что отступ нам не нужен
// Конечно, теперь чтение/запись i может быть медленнее на некоторых процессорах, отступ всё же не для красоты был
Writeln(f3.TSize);
end.