Собственно, @Admin, надеюсь в этот раз вы прочитаете в чём проблема не совместимости, хотя бы перед тем как читать следующее:
Чтоб привести работу типизированных файлов к стандартной, той что закладывал Вирт - надо сделать чтоб записи читались блоками. Костыли из считывания по 1 полю может поверхностно и работают примерно так же, но это полностью избавляет типизированные файлы от всех их преимуществ. Кроме того, даже если исправить строки - метод которым сохранялись записи у Вирта - сохраняет все поля записи, даже приватные. А ваш сохраняет только публичные. Это уже можно исправить только читая блоками.
Я сделал коротенькую демонстрацию на сколько более простой становится запись файлов, если записывать переменные 1 блоком, а не по 1 полю. Конечно, короткие строки надо переделать, потому что если их оставлять ссылочными - кина не будет. Но это не так уж сложно + кода на новые короткие строки надо меньше, чем то сколько съэкономится если переделать типизированные файлы на чтение блоками:
uses System.Runtime.InteropServices;
type
[StructLayout(LayoutKind.&Explicit)]
MyShortString5 = record//короткая строка, реализованная на value-типе
public const MaxLength: byte = 5;//это единственное что надо поменять, чтоб получилась короткая строка с другой длинной
private [FieldOffset(0)]_length: byte;
private [FieldOffset(MaxLength)]last: byte;
public property Length: byte read _length;
public class function operator implicit(s: string): MyShortString5;
begin
Result._length := Min(MaxLength, s.Length);
var ptr_id := integer(@Result._length);//когда (если) добавят арифметику указателей - можно будет слегка упростить
foreach var ch in s.Take(Result._length) do
begin
ptr_id += 1;
PByte(pointer(ptr_id))^ := OrdAnsi(ch);
end;
end;
public class function operator implicit(s: MyShortString5): string;
begin
var sb := new StringBuilder(s._length);
var ptr_id := integer(@s._length);//когда (если) добавят арифметику указателей - можно будет слегка упростить
loop s._length do
begin
ptr_id += 1;
sb += ChrAnsi(PByte(pointer(ptr_id))^);
end;
Result := sb.ToString;
end;
public function ToString: string; override := self;
//ToDo реализовать остальной функционал, который нужен чтоб этот тип работал во всём как string. То есть наследование от sequence и т.п.
end;
procedure TestMyShortString5;
begin
writeln(sizeof(MyShortString5));//6, потому что length(1) + само значение( MaxLength(5)*byte_per_char(1) )
var s: MyShortString5;
s := 'abc';
writeln(s);//abc
//writeln(string(s));//не abc а мусор, потому что #1041
writeln(s.ToString);//abc
end;
type
r1 = record
public x1: byte;
internal s: MyShortString5;//internal и private поля тоже может сохранить, в отличии от вашего file of T
private x2: byte;
public function ToString:string; override :=
$'({x1}, {s}, {x2})';//чтоб writeln выводило internal и private поле. Их всё равно сохраняет в файл, но без этого не выведет в консоль
end;
type
MyFileOf<T>=class
where T: record;
private class sz: integer;
private fi:System.IO.FileInfo;
private bw:System.IO.BinaryWriter;
private br:System.IO.BinaryReader;
private class constructor;
begin
sz := Marshal.SizeOf(typeof(T));
end;
//procedure Rewrite;
public procedure Rewrite(fname:string);
begin
fi := new System.IO.FileInfo(fname);
bw := new System.IO.BinaryWriter(fi.Open(System.IO.FileMode.Create));
end;
public procedure Reset;
begin
br := new System.IO.BinaryReader(fi.Open(System.IO.FileMode.Open));
end;
//procedure Reset(fname:string);
public procedure Write(o: T);
begin
var a := new byte[sz];
var ptr:^T := pointer(@a[0]);
ptr^ := o;
bw.Write(a);
end;
public procedure Write(params a:array of T) :=
foreach var o in a do
Write(o);
public function Read:T;
begin
var a := br.ReadBytes(sz);
var ptr:^T := pointer(@a[0]);
Result := ptr^;
end;
public procedure Close;
begin
if bw <> nil then bw.Close;
if br <> nil then br.Close;
end;
//ToDo реализовать остальной функционал, который нужен чтоб этот тип работал во всём как file of T. К примеру, сделать Rewrite и т.п. Глобальными процедурами PABCSystem
end;
procedure TestMyFileOfT;
begin
var f := new MyFileOf<r1>;
f.Rewrite('temp.bin');
var a:r1;
a.x1 := 255;
a.s := 'abc';
a.x2 := 254;
f.Write(a);
f.Close;
f.Reset;
var b := f.Read;
f.Close;
writeln(a);//(255,abc,254)
writeln(b);//(255,abc,254)
end;
begin
//TestMyShortString5;
TestMyFileOfT;
end.
Эта программа записывает переменную типа записи r1
в файл и успешно загружает её назад. Делается это всё 1 блоком, надеюсь мне не придётся доказывать что это не только проще выглядит, но ещё и работает быстрее. (ну и, конечно, работает именно так как задумывал Вирт, в отличии от вашего file of T
)
Запись содержит короткую строку, реализованую в виде value
-типа (но т.к. это короткая демонстрация - я реализовал не все возможности, только основные, чтоб не забивать пример).
Формат сохранения (в том числе и строки) абсолютно идентичен тому что придумывал Вирт, для всех значений максимальной длинны короткой строки от 0 до 255. (я проверил не каждое значение, но несколько, в том числе крайние)
Я готов доделать такие типизированные файлы и короткие строки, добавив все остальные возможности которых у них не хватает в этом примере, мне нужно лишь ваше разрешение и небольшая помощь, приделать то что получится в итоге к синтаксису.