Як зберегти в файл і завантажити з файлу безрозмірний масив

Як зберегти в файл і завантажити з файлу безрозмірний масив

Сабж.
При завантаженні розмір масиву невідомий. Як зберегти масив в файл разом з інформацією про розмірності, а потім завантажити його звідти, щоб розмірність масиву встановилася такою, якою була при збереженні?

зберегти спочатку розмір, потім сам масив.

а взагалі досвід запису / читання в / з файл (а) маєш?

> В файл разом з інформацією про розмірності

тобто наприклад створити FileStream спочатку записати розмір
Length (Array), SizeOf (Integer)) потім сам масив або за елементами або відразу весь блок

хіба ти не в змозі прочитати елементи інф-ції про размерностях масиву в змінну.
а потім, перед збереженням власне даних масиву, записати в файл значення цих змінних.
з тим щоб при читанні з файлу встановити розмірності масиву соотв.образом, перед тим як зчитувати в масив слідом йдуть в файлі власне дані.

є ж ф-ції TVarData, VarArrayDimCount (), VarArrayLow / HighBound () та ін.
вони дозволять отримати інф-цію про структуру масиву, з тим щоб зберігши / прочитавши її можна було б відновити структуру відтворюваного масиву банальним викликом VarArrayCreate ()

В стані. Але я думав що є простіший спосіб, і вважав що так як я думаю зробити було б по-ламерскі.

Все-таки вирішив спробувати окремо не зберігати в файлі змінну з кол. записів. Написав ось це щось, але воно не працює. Не можу зрозуміти в чому справа.


type
InfoNode = record
parent: integer;
fileNum: cardinal;
text: string [120];
end;
.

NodeList: array of InfoNode;
.

// Збереження списку вузлів в масив, а потім в файл
procedure TForm1.NodeSave;
var
f: file;
i, k: integer;
begin
k: = TreeView1.Items.Count;
SetLength (nodelist, k); // в прикладі число вузлів - 11
for i: = 0 to k-1 do
begin
with Treeview1.items.Item [i] do
begin
if parent = nil then nodelist [i] .Parent: = 99999999 else
nodelist [i] .parent: = parent.absoluteindex;
nodelist [i] .text: = text;
nodelist [i] .fileNum: = cardinal (data);
end;
end;
RichEdit1.lines.add (inttostr (sizeof (nodelist))); // Тут ми бачимо 4
RichEdit1.lines.add (inttostr (TreeView1.items.count)); // хоча тут 11

assignfile (f, "nodelist.dat");
rewrite (f, 128);
blockwrite (f, nodelist, k);
closefile (f);
end;

// Завантаження з файлу
procedure TForm1.NodeLoad;
var
f: file;
begin
assignfile (f, "nodelist.dat");
reset (f, 128);
SetLength (nodelist, FileSize (f));
blockread (f, nodelist, Filesize (f));
RichEdit1.lines.add (inttostr (filesize (f))); // Тут бачимо 11
closefile (f);
RichEdit1.lines.add (nodelist [2] .text); // А тут порожньо хоча у вузла в text щось було.
end;

Все-таки вирішив спробувати окремо не зберігати в файлі змінну з кол. записів. Написав ось це щось, але воно не працює. Не можу зрозуміти в чому справа.


type
InfoNode = record
parent: integer;
fileNum: cardinal;
text: string [120];
end;
.

NodeList: array of InfoNode;
.

// Збереження списку вузлів в масив, а потім в файл
procedure TForm1.NodeSave;
var
f: file;
i, k: integer;
begin
k: = TreeView1.Items.Count;
SetLength (nodelist, k); // в прикладі число вузлів - 11
for i: = 0 to k-1 do
begin
with Treeview1.items.Item [i] do
begin
if parent = nil then nodelist [i] .Parent: = 99999999 else
nodelist [i] .parent: = parent.absoluteindex;
nodelist [i] .text: = text;
nodelist [i] .fileNum: = cardinal (data);
end;
end;
RichEdit1.lines.add (inttostr (sizeof (nodelist))); // Тут ми бачимо 4
RichEdit1.lines.add (inttostr (TreeView1.items.count)); // хоча тут 11

assignfile (f, "nodelist.dat");
rewrite (f, 128);
blockwrite (f, nodelist, k);
closefile (f);
end;

// Завантаження з файлу
procedure TForm1.NodeLoad;
var
f: file;
begin
assignfile (f, "nodelist.dat");
reset (f, 128);
SetLength (nodelist, FileSize (f));
blockread (f, nodelist, Filesize (f));
RichEdit1.lines.add (inttostr (filesize (f))); // Тут бачимо 11
closefile (f);
RichEdit1.lines.add (nodelist [2] .text); // А тут порожньо хоча у вузла в text щось було.
end;

RichEdit1.lines.add (inttostr (sizeof (nodelist))); // Тут ми бачимо 4

Розберися чому і багато що стане ясно.

Я пропоную ВЗЯТИ БУДЬ-НЕБУДЬ ListBox або Memo. і потім зберігати їх дані таким чином Memo1.Lines.SaveToFile ( "1.txt"); А завантажувати Memo1.Lines.LoadFromFile ( "1.txt"); Потім дивишся кількість рядків в Memo - Memo1.Lines.Count (ОСЬ ТОБІ І ДОВЖИНА МАСИВУ). Я майже завжди так роблю, коли у мене масив повинен створюватися динамічно або невідома його довжина.

Так адже я для цього і прошу Вашої допомоги.

прочитай що є SizeOf

Length (nodelist) - довжина масиву (11)
Length (nodelist) * sizeof (InfoNode) - розмір масиву

але ж я також можу переписати все це використовуючи read, readln, write, writeln і працювати з текстовим файлом.
Але на мою думку у мене проблеми саме з тим що масив динамічний, а з такими масивами я раніше не пробував працювати. А писати щось типу NodeList: array [0..10000] of InfoNode; де оголошувати масив з кол. елементів, яке буде напевно перевищувати необхідне значення, мені якось не подобається.
До того ж хочеться дізнатися що я все ж тут не так "намутив".

TFileStream, TWriter + TWriter.WriteListBegin + TWriter.WriteListEnd + методи записи різних типів даних у TWriter
+ ітерація по масиву

Тоді створи Мемо або ListBox теж динамічно і вставляй, і жени скільки влізе. Таке рішення підійде?

assignfile (f, "nodelist.dat");
rewrite (f);
blockwrite (f, nodelist [0], Length (nodelist) * sizeof (InfoNode));
closefile (f);

assignfile (f, "nodelist.dat");
SetLength (nodelist, FileSize (f) div sizeof (InfoNode));
blockread (f, nodelist [0], Filesize (f));
closefile (f);

assignfile (f, "nodelist.dat");
reset (f);
SetLength (nodelist, FileSize (f) div sizeof (InfoNode));
blockread (f, nodelist [0], Filesize (f));
closefile (f);


> Я пропоную ВЗЯТИ БУДЬ-НЕБУДЬ ListBox або Memo, і потім
> Зберігати їх дані таким чином Memo1.Lines.SaveToFile ( "1.txt");
> А завантажувати Memo1.Lines.LoadFromFile ( "1.txt"); потім дивишся
> Кількість рядків в Memo - Memo1.Lines.Count (ОСЬ ТОБІ І ДОВЖИНА
> МАСИВУ). Я майже завжди так роблю, коли у мене масив
> Повинен створюватися динамічно або невідома його довжина

Може Tstrings було б зручніше заюзать :)
А так не пробував :)

procedure ReadFile;
var Data: array of Trecord;
f: file of TRecord;
s: string;
i, n: integer;
begin
s: = "d: \ Data.dat";
AssignFile (F, S);
ReWrite (f);
i: = FileSize (f); // довжина масиву;
n: = 0;
SetLength (Data, i);
While not Eof (f) do
begin
Read (f, Data [n]);
inc (n);
end;
CLoseFile (f);
//.
//.
SetLength (data, 0);
end;

procedure SaveFile;
var Data: array of Trecord;
f: file of TRecord;
s: string;
i, n: integer;
begin
s: = "d: \ Data.dat";
AssignFile (F, S);
Reset (f);
for i: = Low (data) to high (data) do write (f, data [i]);
CLoseFile (f); // That "s all :)
end;

Дякуємо. Я зрозумів. Хоча чомусь коли ставив твій код, то вилазила помилка.
Переписав так:

type
InfoNode = record
parent: integer;
fileNum: cardinal;
text: string [116]; // зменшив до 116, щоб sizeof (infonode) = 128
end;

// Запис
assignfile (f, "nodelist.dat");
rewrite (f, 128);
blockwrite (f, nodelist [0], length (NodeList));
closefile (f);

// Читання
assignfile (f, "nodelist.dat");
reset (f, 128);
SetLength (nodelist, FileSize (f));
blockread (f, nodelist [0], Filesize (f));
closefile (f);

Через мій алгоритм можеш хоч і string [255]

assignfile (f, "nodelist.dat");
rewrite (f, 1);
blockwrite (f, nodelist [0], Length (nodelist) * sizeof (InfoNode));
closefile (f);

assignfile (f, "nodelist.dat");
reset (f, 1);
SetLength (nodelist, FileSize (f) div sizeof (InfoNode));
blockread (f, nodelist [0], Filesize (f));
closefile (f);

type
InfoNode = record
parent: integer;
fileNum: cardinal;
text: string [116]; // зменшив до 116, щоб sizeof (infonode) = 128
end;

Хоча є питання. Начебто integer і cardinal займають по 4 байти, разом 4 + 4 + 116 = 124, а sizeof (infonode) = 128.

тільки
assignfile (f, "nodelist.dat");
rewrite (f, sizeof (InfoNode)); // -.
blockwrite (f, nodelist [0], length (NodeList));
closefile (f);

rewrite (f, 1);
reset (f, 1);

М-да. Я забув що за замовчуванням буде 128.

Ну це вже не проблема.
Я не пробував але думаю що можна і так:
reset (f, sizeof (infonode));

До речі якщо зберегти
blockwrite (f, Pointer (Integer (nodelist [0]) - 4), length (NodeList) +4); то в файл запишеться і довжина масиву.

Схожі статті