Форум программистов, компьютерный форум, киберфорум
Delphi
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.83/18: Рейтинг темы: голосов - 18, средняя оценка - 4.83
 Аватар для NapalmRain
44 / 43 / 7
Регистрация: 18.05.2010
Сообщений: 688

Сохранения XML в бинарный файл

03.12.2013, 17:56. Показов 3878. Ответов 16
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Есть XML, работаю с ним через XMLDocument
Всё прекрасно, всё хорошо.
Но вот хочу попробовать такой вариант: Сохранить этот самый XML после редактирования в некий бинарный файл.
Я знаю, что текстовый документ является частный случаем бинарного. В данном конкретном случае я имею ввиду что-нибудь, что в каком-нибудь блокноте будет выглядеть как нечитаемая вязь.
Пробовал записывать и считывать построчно через shortstring, Получается не очень корректно, при считывании есть ошибки в тексте, не хватает символов, появляются лишние пробелы и т.д.
Пробовал через WriteBlock/ReadBlock. C записью проблем нет, а вот как потом реализовать считывание корректно, так же не придумал.
Буду благодарен за любого рода подсказку.
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
03.12.2013, 17:56
Ответы с готовыми решениями:

Класс сохранения данных в xml
Всем привет. Есть ли класс для сохранения данных в xml, данные разных типов вкл массивы и tstringlist. Что бы легко было использовать.

Запись разнообразных данных в бинарный файл (как лучше сделать?)
Собственно вопрос таков, имеются очень много структур данных(записи), как их лучше всего записать в файл, чтобы потом читать без головной...

Бинарный файл
Есть поля записи которые вводятся в бинарный файл. Скажите пожалуйста какой компонент наиболее наглядно подходит для вывода всего...

16
3530 / 2270 / 279
Регистрация: 24.12.2010
Сообщений: 13,723
03.12.2013, 22:41
Да просто сожми текстовые данные средствами zlib - вот и будут бинарные.
А перед чтением в xmldocument разожми их теми же средствами zlib - данные станут вновь текстовыми
1
 Аватар для NapalmRain
44 / 43 / 7
Регистрация: 18.05.2010
Сообщений: 688
04.12.2013, 10:31  [ТС]
Вполне приемлемая идея. Благодарю за совет.
Я, правда, дошёл до мысли просто сохранять данные в типизированном файле. Но можно и вовсе совместить)
0
 Аватар для Mawrat
13116 / 5897 / 1708
Регистрация: 19.09.2009
Сообщений: 8,809
04.12.2013, 12:53
Можно в Base64 кодировать/декодировать.
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
uses
  EncdDecd;
 
//Закодировать в Base64.
procedure TForm1.Button1Click(Sender: TObject);
begin
  //Закодировать в Base64 и записать в Мемо2.
  Memo2.Text := EncodeString(Memo1.Text);
end;
 
//Раскодировать из Base64.
procedure TForm1.Button2Click(Sender: TObject);
begin
  //Раскодировать из Base64 и записать в Мемо1.
  Memo1.Text := DecodeString(Memo2.Text);
end;
1
 Аватар для NapalmRain
44 / 43 / 7
Регистрация: 18.05.2010
Сообщений: 688
04.12.2013, 15:24  [ТС]
Тоже как вариант. А ещё столкнулся сейчас с одной интересной задачей.
Хочу записать всё свой добро в типизированный файл.
Описываю тип и понимаю, что у меня беда:
Delphi
1
2
3
4
5
6
type MyType = Record
    Name: string[255];
    version: integer;
    Author: string[255];
    Content: string[2147483647]; // такой вариант, понятно дело не прокатит, так как максимум 255 символов
  end;
Но как же быть тогда?
Можно ли как-то обойти это ограничение? может быть использовать массив какой-то типа array of char например и записывать в его элементы данные посимвольно? Предварительно указав размер.
Или же можно какой-то иной тип переменной использовать?

Добавлено через 7 минут
Цитата Сообщение от NapalmRain Посмотреть сообщение
может быть использовать массив какой-то типа array of char например и записывать в его элементы данные посимвольно? Предварительно указав размер.
Попробовал, идея с треском провалилась, так как если указать динамический массив, то так же ругается на незавершённость файла, а если брать по максимуму array[0..High(integer)], то говорит: ай-ай-ай два гига - это через чур много.
0
3530 / 2270 / 279
Регистрация: 24.12.2010
Сообщений: 13,723
04.12.2013, 15:27
Цитата Сообщение от NapalmRain Посмотреть сообщение
Хочу записать всё свой добро в типизированный файл
Не получится.
Типизированный файл априори подразумевает один и тот же фиксированный размер любой записи, а у тебя размеры записей заранее неизвестны.

Выход один - сериализация/десериализация объектов-записей.
0
 Аватар для NapalmRain
44 / 43 / 7
Регистрация: 18.05.2010
Сообщений: 688
04.12.2013, 15:38  [ТС]
Цитата Сообщение от mss Посмотреть сообщение
сериализация/десериализация
Я понимаю, что может быть вопрос мой покажется глупым или не серьёзным, но что значат эти страшные слова?

Добавлено через 8 минут
mss, сейчас немного почитал об этом понятии в целом.
Поправьте меня, если я думаю не в том направлении.
То есть, я в принципе могу засунуть XMLDocument1, который содержит мою информацию в поток памяти и оттуда записать его в файл, а потом вынуть назад?
0
3530 / 2270 / 279
Регистрация: 24.12.2010
Сообщений: 13,723
04.12.2013, 15:46
Цитата Сообщение от NapalmRain Посмотреть сообщение
засунуть ..информацию в поток памяти и оттуда записать его в файл, а потом вынуть назад
Да.
Можно и сразу в файловый поток записывать.
Собственно содержимое любого xml-файла и есть ничто иное как сериализованый объект.
0
 Аватар для NapalmRain
44 / 43 / 7
Регистрация: 18.05.2010
Сообщений: 688
04.12.2013, 16:01  [ТС]
mss, спасибо, попробую смотреть в этом направлении, но всё таки интересно, неужели никак нельзя организовать собственный тип файла, с изначально неизвестной длинной данных.
Может как-то есть возможность обойти данное ограничение?
Или только если указывать максимально возможные размеры, работать с ними, сохранять, оставляя половину, а то и более памяти неиспользованной?
0
3530 / 2270 / 279
Регистрация: 24.12.2010
Сообщений: 13,723
04.12.2013, 16:10
Цитата Сообщение от NapalmRain Посмотреть сообщение
неужели никак нельзя организовать собственный тип файла, с изначально неизвестной длинной данных
Почему нельзя ? Можно)
Но в твоем случае он не может быть типизированным.
0
 Аватар для NapalmRain
44 / 43 / 7
Регистрация: 18.05.2010
Сообщений: 688
04.12.2013, 16:19  [ТС]
Цитата Сообщение от mss Посмотреть сообщение
Почему нельзя ? Можно)
Но в твоем случае он не может быть типизированным.
Понял принял, спасибо.
Я понимаю, что это уже оффтоп, но если не сложно, был бы признателен за информацию по данному вопросу(создание типизированного документа с изначально неизвестной длинной данных).
0
 Аватар для Mawrat
13116 / 5897 / 1708
Регистрация: 19.09.2009
Сообщений: 8,809
04.12.2013, 16:45
Файл будет нетипизированным. Как выше в теме уже упоминалось - в него можно записать данные переменной длины. Делать можно через типовой подход - если надо сохранить некоторые данные, то сначала в файл записываем сведения о размере этих данных в байтах (Size : Integer), а потом записываем сами данные. Т. е., например, если надо записать строку, то сначала записываем размер строки (размер - в байтах), а затем записываем текстовые данные строки.
При чтении действуем так. Сначала читаем сведения о размере данных (например - это размер текстовых данных строки), потом выделяем память для данных (для строки), затем, читаем данные из файла и записываем их в выделенную область памяти.
Выглядеть это будет так:
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
implementation
 
{$R *.dfm}
 
type
  TRec = record
    Name, Version, Author, Content : String;
  end;
 
//Чтение записи из файла.
procedure ReadRec(const aF: File; var aRec : TRec);
var
  Size : Integer;
begin
  //Чтение поля Name.
  BlockRead(aF, Size, SizeOf(Size)); //Чтение сведений о размере данных (количество байт).
  SetLength(aRec.Name, Size div SizeOf(Char)); //Выделяем память для строки.
  BlockRead(aF, aRec.Name[1], Size); //Чтение данных и их запись в строку.
  //Чтение поля Version.
  BlockRead(aF, Size, SizeOf(Size));
  SetLength(aRec.Version, Size div SizeOf(Char));
  BlockRead(aF, aRec.Version[1], Size);
  //Чтение поля Author.
  BlockRead(aF, Size, SizeOf(Size));
  SetLength(aRec.Author, Size div SizeOf(Char));
  BlockRead(aF, aRec.Author[1], Size);
  //Чтение поля Content.
  BlockRead(aF, Size, SizeOf(Size));
  SetLength(aRec.Content, Size div SizeOf(Char));
  BlockRead(aF, aRec.Content[1], Size);
end;
 
//Запись элемента (записи) в файл.
procedure WriteRec(const aF: File; const aRec : TRec);
var
  Size : Integer;
begin
  //Запись поля Name.
  Size := Length(aRec.Name) * SizeOf(Char); //Размер данных в байтах.
  BlockWrite(aF, Size, SizeOf(Size));       //Запись сведений о размере.
  BlockWrite(aF, aRec.Name[1], Size);       //Запись данных.
  //Запись поля Version.
  Size := Length(aRec.Version) * SizeOf(Char);
  BlockWrite(aF, Size, SizeOf(Size));
  BlockWrite(aF, aRec.Version[1], Size);
  //Запись поля Author.
  Size := Length(aRec.Author) * SizeOf(Char);
  BlockWrite(aF, Size, SizeOf(Size));
  BlockWrite(aF, aRec.Author[1], Size);
  //Запись поля Content.
  Size := Length(aRec.Content) * SizeOf(Char);
  BlockWrite(aF, Size, SizeOf(Size));
  BlockWrite(aF, aRec.Content[1], Size);
end;
 
//Запись элементов переменной длины в файл.
procedure TForm1.Button1Click(Sender: TObject);
const
  Fn = 'file.dat';
  M = 10;
var
  F : File;
  Arr : array of TRec;
  i : Integer;
begin
  //Заполняем массив записей.
  SetLength(Arr, M);
  for i := 0 to High(Arr) do
  begin
    Arr[i].Name := 'Name: ' + FormatFloat('00', i);
    Arr[i].Version := 'Version: ' + FormatFloat('00', i);
    Arr[i].Author := 'Author: ' + FormatFloat('00', i);
    Arr[i].Content := 'Content: ' + FormatFloat('00', i);
  end;
 
  //Записываем элементы массива в файл.
  AssignFile(F, ExtractFilePath(ParamStr(0)) + Fn);
  Rewrite(F, 1);
  try
    for i := 0 to High(Arr) do
      WriteRec(F, Arr[i]);
  finally
    CloseFile(F);
  end;
  ShowMessage('Данные записаны в файл.');
end;
 
//Чтение элементов переменной длины из файла.
procedure TForm1.Button2Click(Sender: TObject);
const
  Fn = 'file.dat';
var
  F : File;
  Rec : TRec;
begin
  //Читаем элементы из файла и записываем их данные в Memo.
  Memo1.Clear;
  AssignFile(F, ExtractFilePath(ParamStr(0)) + Fn);
  Reset(F, 1);
  try
    while not Eof(F) do
    begin
      ReadRec(F, Rec);
      Memo1.Lines.Add('----------');
      Memo1.Lines.Add(Rec.Name);
      Memo1.Lines.Add(Rec.Version);
      Memo1.Lines.Add(Rec.Author);
      Memo1.Lines.Add(Rec.Content);
    end;
  finally
    CloseFile(F);
  end;
end;
 
end.
1
 Аватар для NapalmRain
44 / 43 / 7
Регистрация: 18.05.2010
Сообщений: 688
04.12.2013, 17:21  [ТС]
Mawrat, понял ещё раз, что ещё учиться и учиться.
Так или иначе, благодарю!
Всё прекрасно. Правда по началу не поняв зачем в процедурах установлено Name[1] словил ошибку доступа, удалив этот указатель. Но разобравшись, откуда ноги растут, вернул назад и получил всё что нужно.
0
 Аватар для Mawrat
13116 / 5897 / 1708
Регистрация: 19.09.2009
Сообщений: 8,809
04.12.2013, 20:41
Цитата Сообщение от NapalmRain Посмотреть сообщение
Всё прекрасно. Правда по началу не поняв зачем в процедурах установлено Name[1] словил ошибку доступа, удалив этот указатель. Но разобравшись, откуда ноги растут, вернул назад и получил всё что нужно.
aRec.Name имеет тип String. Это означает, что aRec.Name, на самом деле, является указателем на область памяти, в которой располагаются текстовые данные строки. А aRec.Name[1] - это объект данных, который располагается в самом начале блока памяти, который содержит текстовые данные строки. Вот поэтому мы указываем в процедурах BlockRead() и BlockWrite() aRec.Name[1], а не aRec.Name.

Следующая версия кода. Более гибкий подход:
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
implementation
 
{$R *.dfm}
 
type
  TRec = record
    Name, Version, Author, Content : String;
  end;
 
//Чтение строки из файла.
function ReadStr(const aF: File) : String;
var
  Size : Integer;
begin
  BlockRead(aF, Size, SizeOf(Size)); //Чтение сведений о размере данных (количество байт).
  SetLength(Result, Size div SizeOf(Char)); //Выделяем память для строки.
  BlockRead(aF, Result[1], Size); //Чтение данных и их запись в строку.
end;
 
//Запись строки в файл.
procedure WriteStr(const aF: File; const aStr : String);
var
  Size : Integer;
begin
  Size := Length(aStr) * SizeOf(Char); //Размер данных в байтах.
  BlockWrite(aF, Size, SizeOf(Size));  //Запись сведений о размере.
  BlockWrite(aF, aStr[1], Size);       //Запись данных.
end;
 
//Чтение элемента из файла.
procedure ReadRec(const aF: File; var aRec : TRec);
begin
  aRec.Name := ReadStr(aF);
  aRec.Version := ReadStr(aF);
  aRec.Author := ReadStr(aF);
  aRec.Content := ReadStr(aF);
end;
 
//Запись элемента в файл.
procedure WriteRec(const aF: File; const aRec : TRec);
begin
  WriteStr(aF, aRec.Name);
  WriteStr(aF, aRec.Version);
  WriteStr(aF, aRec.Author);
  WriteStr(aF, aRec.Content);
end;
 
//Запись элементов переменной длины в файл.
procedure TForm1.Button1Click(Sender: TObject);
const
  Fn = 'file.dat';
  M = 10;
var
  F : File;
  Arr : array of TRec;
  i : Integer;
begin
  //Заполняем массив записей.
  SetLength(Arr, M);
  for i := 0 to High(Arr) do
  begin
    Arr[i].Name := 'Name: ' + FormatFloat('00', i);
    Arr[i].Version := 'Version: ' + FormatFloat('00', i);
    Arr[i].Author := 'Author: ' + FormatFloat('00', i);
    Arr[i].Content := 'Content: ' + FormatFloat('00', i);
  end;
 
  //Записываем элементы массива в файл.
  AssignFile(F, ExtractFilePath(ParamStr(0)) + Fn);
  Rewrite(F, 1);
  try
    for i := 0 to High(Arr) do
      WriteRec(F, Arr[i]);
  finally
    CloseFile(F);
  end;
  ShowMessage('Данные записаны в файл.');
end;
 
//Чтение элементов переменной длины из файла.
procedure TForm1.Button2Click(Sender: TObject);
const
  Fn = 'file.dat';
var
  F : File;
  Rec : TRec;
begin
  //Читаем элементы из файла и записываем их данные в Memo.
  Memo1.Clear;
  AssignFile(F, ExtractFilePath(ParamStr(0)) + Fn);
  Reset(F, 1);
  try
    while not Eof(F) do
    begin
      ReadRec(F, Rec);
      Memo1.Lines.Add('----------');
      Memo1.Lines.Add(Rec.Name);
      Memo1.Lines.Add(Rec.Version);
      Memo1.Lines.Add(Rec.Author);
      Memo1.Lines.Add(Rec.Content);
    end;
  finally
    CloseFile(F);
  end;
end;
 
end.
0
Заблокирован
04.12.2013, 21:30
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
unit Unit1;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;
 
type
  TForm1 = class(TForm)
    Memo1: TMemo;
    procedure Memo1Change(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
  TMyStr = class(TComponent)
  private
    FStr: String;
    procedure ReadStrings(Reader: TReader);
    procedure WriteStrings(Writer: TWriter);
  public
    procedure DefineProperties(Filer: TFiler); override;
    property Str: String read FStr write FStr;
  end;
 
var
  Form1: TForm1;
  MyStr: TMyStr;
 
implementation
 
{$R *.dfm}
 
{ TMyStr }
 
procedure TMyStr.DefineProperties(Filer: TFiler);
begin
  inherited;
  Filer.DefineProperty('MyStr', ReadStrings, WriteStrings, True);
end;
 
procedure TMyStr.ReadStrings(Reader: TReader);
begin
  Str := Reader.ReadString;
end;
 
procedure TMyStr.WriteStrings(Writer: TWriter);
begin
  Writer.WriteString(Str);
end;
 
procedure TForm1.Memo1Change(Sender: TObject);
begin
  MyStr.Str := Memo1.Text;
  WriteComponentResFile('ôàåë', MyStr);
end;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  if FileExists('ôàåë') then  MyStr := ReadComponentResFile('ôàåë', nil) as TMyStr
  else MyStr := TMyStr.Create(nil);
  Memo1.Text := MyStr.Str;
end;
 
procedure TForm1.FormDestroy(Sender: TObject);
begin
  FreeAndNil(MyStr);
end;
 
initialization
  RegisterClass(TMyStr);
 
end.
2
3530 / 2270 / 279
Регистрация: 24.12.2010
Сообщений: 13,723
04.12.2013, 21:48
Лучший ответ Сообщение было отмечено как решение

Решение

Для простейшего случая со св-вами основных типов (к коим относится String) будет еще проще:

TMyStr = class(TComponent)
private
FStr: String;
procedure ReadStrings(Reader: TReader);
procedure WriteStrings(Writer: TWriter);
public published
procedure DefineProperties(Filer: TFiler); override;
property Str: String read FStr write FStr;
end;
3
 Аватар для NapalmRain
44 / 43 / 7
Регистрация: 18.05.2010
Сообщений: 688
05.12.2013, 11:32  [ТС]
Всем спасибо!
Идею понял. Буду дальше уже думать. Благо понял, в каком направлении.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
05.12.2013, 11:32
Помогаю со студенческими работами здесь

Бинарный файл
Загрузка в RichEdit: Red2.Text := BinaryP(OpenDialog1.FileName); Как преобразовать обратно? function BinaryP(filename: string):...

Создать бинарный файл
Здравствуйте, подскажите как создать бинарный файл на компьютере через delphi Т.е. чтобы бинарный код был записан в приложении, после...

Как записать в бинарный файл
Как записать какой-нибуть текст в бинарный файл?

Создать бинарный файл записей
Создать бинарный файл структур, содержащих сведения о студентах. Структура имеет следующий вид: Struct XX{ //студент Char N; ...

Бинарный текст в бинарый файл!
Помогите пожалуйста! У меня есть MEMO, в нем текст вида "1011111101010101010" и ничего больше! Вопрос: КАК ДВОИЧНЫЙ ТЕКСТ СОХРАНИТЬ В...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
17
Ответ Создать тему
Новые блоги и статьи
Доступность команды формы по условию
Maks 07.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: сделать доступной кнопку (команда формы "ЗавершитьСписание") при. . .
Уведомление о неверно выбранном значении справочника
Maks 06.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "НарядПутевка", разработанного в конфигурации КА2. Задача: уведомлять пользователя, если в документе выбран неверный склад. . .
Установка Qt Creator для C и C++: ставим среду, CMake и MinGW без фреймворка Qt
8Observer8 05.04.2026
Среду разработки Qt Creator можно установить без фреймворка Qt. Есть отдельный репозиторий для этой среды: https:/ / github. com/ qt-creator/ qt-creator, где можно скачать установщик, на вкладке Releases:. . .
AkelPad-скрипты, структуры, и немного лирики..
testuser2 05.04.2026
Такая программа, как AkelPad существует уже давно, и также давно существуют скрипты под нее. Тем не менее, прога живет, периодически что-то не спеша дополняется, улучшается. Что меня в первую очередь. . .
Отображение реквизитов в документе по условию и контроль их заполнения
Maks 04.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеСпецтехники", разработанного в конфигурации КА2. Данный документ берёт данные из другого нетипового документа. . .
Фото всей Земли с борта корабля Orion миссии Artemis II
kumehtar 04.04.2026
Это первое подобное фото сделанное человеком за 50 лет. Снимок называют новым вариантом легендарной фотографии «The Blue Marble» 1972 года, сделанной с борта корабля «Аполлон-17». Новое фото. . .
Вывод диалогового окна перед закрытием, если документ не проведён
Maks 04.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: реализовать программный контроль на предмет проведения документа. . .
Программный контроль заполнения реквизитов табличной части документа
Maks 02.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: 1. Реализовать контроль заполнения реквизита. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru