Форум программистов, компьютерный форум, киберфорум
Delphi
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.61/18: Рейтинг темы: голосов - 18, средняя оценка - 4.61
58 / 24 / 6
Регистрация: 26.09.2010
Сообщений: 241

Динамические данные в типизированный файл

11.12.2011, 23:01. Показов 3343. Ответов 13
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Всем привет!

Имеется структура с динамическим массивом

Delphi
1
2
3
4
5
6
7
8
type
  TStateItem = record
    Index: String[10];
    State1, State2: String[50];
 
var
  StateBaseFile: file of TStateItem;
  StateBase: array of TStateItem;
Работаем с типизированным файлом через Read и Write.

А вот проблема... Если понадобится чтобы в этот же файл записать данные, при том что State может быть от одного до StateN. Как вообще хранить такие данные в памяти, и как записать в файл?

P.S. Или даже так. Как данные такого типа
Delphi
1
2
3
type
  TStateItem = record
    State: array of String;
записывать в файлы и считывать?
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
11.12.2011, 23:01
Ответы с готовыми решениями:

Типизированный файл
Информация о сотрудниках фирмы включает: Ф.И.О., табельный номер, количество проработанных часов за месяц, почасовой тариф. Рабочее время...

Не создается типизированный файл
Здравствуйте, уважаемые форумчане. Прошу Вас помочь мне. unit Unit1; interface uses Windows, Messages, SysUtils, Variants,...

Вывод в типизированный файл
скажите пожайлуста как из memo вывести данные в файл f:file of real

13
 Аватар для pHOMM
480 / 253 / 51
Регистрация: 30.06.2010
Сообщений: 651
12.12.2011, 12:55
Строки (по умолчанию в дельфи от 2 или 3 версии, не помню конкретно, но в 6 и 7 и выше - точно - string это есть ansistring и она является автоуправляемым ссылочным типом) надо писать разыменовывая указатель на строку- делается это через обращение к первому её символу
примерно так (примерно - потому что я не работаю с паскаль-файлами, а с потоками, и пишу по памяти) : blockread(ourfile, ourstr[1], ourstrlength); а писать write(ourfile, ourstr); нельзя никогда, ибо запишется только указатель на строку - а это просто 4байтное число адреса
0
58 / 24 / 6
Регистрация: 26.09.2010
Сообщений: 241
12.12.2011, 13:17  [ТС]
Да, кстати Delphi7 юзаю.

Вобщем прошла такая конструкция
Delphi
1
2
3
4
5
6
7
8
9
type
  TStateItem = record
    Index: String[10];
    Key: array of Integer;
    Data: array of String;
  end;
 
var
  ConfigBase: array of TStateItem;
Ну это с массивом в памяти.

А теперь для сохранения и считывания вот такого массива, как раз и использую TFileStream.

Добавлено через 3 минуты
Получается для записи строки S (типа String) нельзя использовать
Delphi
1
Stream.WriteBuffer(s, L);
а надо обязательно
Delphi
1
Stream.WriteBuffer(s[1], L);
так???
0
 Аватар для pHOMM
480 / 253 / 51
Регистрация: 30.06.2010
Сообщений: 651
12.12.2011, 17:03
Ну, да )) достаточно попробовать ведь ))
Кстати откуда L берете ?

Я вообще часто использую файлстримы - позволяет не заботиться о типизации файлов и разнобое команд управления(потоки Stream они как и остальные объекты управляются)
но, вообще файлстрим он аналогичен file of byte по схеме работы, но удобнее
1
58 / 24 / 6
Регистрация: 26.09.2010
Сообщений: 241
12.12.2011, 20:43  [ТС]
Спасибо. Все разобрался, сделал как надо.

Цитата Сообщение от pHOMM Посмотреть сообщение
Кстати откуда L берете ?
L = SizeOf(s);
0
 Аватар для Mawrat
13114 / 5895 / 1708
Регистрация: 19.09.2009
Сообщений: 8,809
13.12.2011, 04:29
Цитата Сообщение от Sergio-X86 Посмотреть сообщение
L = SizeOf(s);
Если S - это String, то SizeOf(S) всегда будет равен 4. Потому что S - это на самом деле указатель. - pHOMM, об этом уже говорил выше. И он не зря произнёс эту фразу:
Цитата Сообщение от pHOMM Посмотреть сообщение
Кстати откуда L берете ?
Дело в том, что указатель в памяти занимает всегда 4 байта - это значение никак не зависит от длины строки. Поэтому количество символов строки надо определять так:
Delphi
1
L := Length(S);
А размер данных строки в байтах определяется так:
Delphi
1
Size := Length(S) * SizeOf(Char);
В Delphi7 тип Char соответствует типу AnsiChar и в памяти данные такого типа занимают 1 байт. В Delphi 2009/2010/XE тип Char соответствует типу WideChar и в памяти объект этого типа занимает 2 байта. Соответственно, в Delphi7 тип String соответствует типу AnsiString. А в Delphi 2009/2010/XE тип String соответствует типу WideString.
Sergio-X86, чтобы правильно записывать, а потом считывать из фалйа данные переменной длины, необходимо придумать формат файла. И разработать код для записи/чтения. Такой код должен записывать сведения о длине данных, а затем, записывать сами данные. А при чтении надо прочитать сведения о длине, создавать строку соответствующей длины через SetLength(S, L), а затем в эту строку прочитать текстовые данные из файла.
0
58 / 24 / 6
Регистрация: 26.09.2010
Сообщений: 241
13.12.2011, 14:32  [ТС]
Извиняюсь, у меня Length используется для записи строки
Delphi
1
2
3
4
S:= StateItem[i].Data[j]; 
L:= Length(S);
Stream.WriteBuffer(L, SizeOf(L));
Stream.WriteBuffer(s[1], L);
для считывания
Delphi
1
2
3
4
Stream.ReadBuffer(L, SizeOf(L));
SetLength(S, L);
Stream.ReadBuffer(S[1], L);
StateItem[i].Data[j] := S;
Получается в Delphi7 достаточно
Delphi
1
L := Length(S);
или все же надо
Delphi
1
L := Length(S) * SizeOf(Char);
???
0
 Аватар для pHOMM
480 / 253 / 51
Регистрация: 30.06.2010
Сообщений: 651
14.12.2011, 09:59
Для дельфи7 достаточно, но никто Вас не укусит, если Вы предусмотрите *SizeOf(Char) , наоборот даже будут рады если откроют проект на дельфи начиная от 2009 версии.
А вообще всё правильно, я только не знаю, что оптимальнее Read или ReadBuffer, вот чтение из моего проекта (сданого)
Delphi
1
2
3
ms.read(w, sizeof(w));
setlength(str, w);
ms.read(str[1], w);
UPD А всё, поглядел, оптимальнее использовать ReadBuffer, потому что он безопаснее - генерирует исключение при ошибке, а если без ошибок, то он вызывает Read, хотя если Вы не используете исключения, то, в общем, всё равно.
0
 Аватар для Mawrat
13114 / 5895 / 1708
Регистрация: 19.09.2009
Сообщений: 8,809
14.12.2011, 12:37
Ещё при записи/чтении строки из потока желательно писать не S[1], а Pointer(S)^ - это позволить записывать/читать пустые строки.
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var
  S : AnsiString;
  L : Integer;
...
begin
...
  //Запись.
  L := Length(S);
  Stream.Write(L, SizeOf(L));
  Stream.Write(Pointer(S)^, L);
...
  //Чтение.
  Stream.Read(L, SizeOf(L));
  SetLength(S, L);
  Stream.Read(Pointer(S)^, L);
...
1
 Аватар для pHOMM
480 / 253 / 51
Регистрация: 30.06.2010
Сообщений: 651
14.12.2011, 14:06
Я сейчас проверил
по справке пустая строка ссылается на nil
showmessage(st[1]) на пустой строке дает АВ
showmessage(IntToStr(integer(Pointer(st) ^))); тоже дает АВ
showmessage(IntToStr(integer(Pointer(st) ))); дает 0 как и должно (хотя nil не всегда по 0 адресу)

получается как не обращайся к пустой строке, будет АВ, хотя часть методов чтения некоторых stream проверяет на count на 0 и только потом вызывает операцию, но, например, tfilestream.read сразу вызывает fileread (из SysUtils), передавая туда
А вот Readbuffer гарантированно проверяет count на 0 и будет безопасен в этом плане )
1
 Аватар для Mawrat
13114 / 5895 / 1708
Регистрация: 19.09.2009
Сообщений: 8,809
14.12.2011, 16:35
Здесь вот в чём дело.
Цитата Сообщение от pHOMM Посмотреть сообщение
showmessage(st[1]) на пустой строке дает АВ
Потому что st[1] - это не просто обозначение некоторого объекта, а операция перехода по адресу с учётом смещения. Операция [] - это, на самом деле, операция перехода по смещению относительно базового адреса. Поэтому, когда мы пишем st[1], то компилятор должен перейти по адресу Pointer(st), а затем выполнить смещение адреса на велечину (1 - 1)*SizeOf(Char). Но так как Pointer(st) = nil, то попытка выполнить переход по смещению (не важно, что смещение равно нулю) приводит к АВ. Примечание: здесь (1 - 1) - с учётом особенностей механизма обработки строк.
Цитата Сообщение от pHOMM Посмотреть сообщение
showmessage(IntToStr(integer(Pointer(st) ^))); тоже дает АВ
Здесь происходит следующее. Когда мы пишем Pointer(st)^ - мы просто указываем, что якобы по адресу Pointer(st) находится некоторый объект. - Не важно, существует этот объект или нет. А вот когда пишем так: showmessage(IntToStr(integer(Pointer(st) ^))); то мы не просто указываем, что имеется в виду некоторый объект, а делаем попытку прочитать данные этого объекта - поэтому получаем АВ в случае, если st = ''.
Поэтому, в случае если st = '', такой код:
Delphi
1
Stream.Write(st[1], L);
вызовет ошибку (АВ). Потому что произойдёт попытка применить смещение относительно базового адреса Poiner(st).
А когда мы пишем такой код:
Delphi
1
Stream.Write(Pointer(st)^, L);
здесь ошибок не будет. Потому что мы просто указали, что, якобы по адресу Pointer(st) располагается некий объект. И компилятор не выполняет никаких действий по доступу к этому объекту.
---
Краткий итог:
- Выражение st[1] подразумевает, что должна быть выполнена операция перехода по заданному смещению относительно базового адреса Pointer(st). Но так как Pointer(st) = nil, то попытка перехода по смещению приводит к ошибке.
- Выражение Pointer(st)^ не предполагает никаких действий со стороны программы - здесь просто указывается, что по адресу Pointer(st) расположен некоторый объект. Поэтому ошибок не возникает. - Нет действий - нет ошибок.
---
Во всех версиях Delphi всегда выполняется правило: Integer(nil) = 0. Хотя, на уровне операционной системы, считается, вроде, что все указатели, которые имеют адрес меньший 100, являются нулевыми.
0
 Аватар для pHOMM
480 / 253 / 51
Регистрация: 30.06.2010
Сообщений: 651
15.12.2011, 09:26
Хе , мои опыты(д7 но имхо на любой будет, могу и д2007 погонять) :
Везде подразумевается что поток декларирован именно того типа, которым инстанцируется. Строка - пустая, т.е. её указатель = nil. Режим создания Tfilestream - соответствующий операции, файл непустой.
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
stm := TmemoryStream.Create();
stm.Write(str[1], 1); // av
stm.read(str[1], 1); // ok 
 
stm := TmemoryStream.Create();
stm.Write(pointer(str)^, 1); // av
stm.read(pointer(str)^, 1); // ok 
 
stm := TfileStream.Create(...);
stm.Write(str[1], 1); // ok
stm.read(str[1], 1); // ok 
 
stm := TfileStream.Create(...);
stm.Write(pointer(str)^, 1); // ok
stm.read(pointer(str)^, 1); // ok 
 
stm := TmemoryStream.Create(); 
stm.Write(str[1], 0); // ok
// чтение 0 байт из стримов аналогично чтению 1 байта , т.е. везде ок
 
stm := TmemoryStream.Create();
stm.Write(pointer(str)^, 0); // ok
 
stm := TfileStream.Create(...);
stm.Write(str[1], 0); // ok 
 
stm := TfileStream.Create(...);
stm.Write(pointer(str)^, 0); // ok
В общем, судите сами. Думаю, способы обращения к пустым строкам в потоках вполне идентичны, Надо будет ещё ассемблерный код, генерируемый ими рассмотреть или призвать в тред GunSmoker'a )) он объяснит
2
58 / 24 / 6
Регистрация: 26.09.2010
Сообщений: 241
17.12.2011, 12:33  [ТС]
Да, интересная информация Еще было бы хорошо и GunSmoker'a послушать.
0
 Аватар для Mawrat
13114 / 5895 / 1708
Регистрация: 19.09.2009
Сообщений: 8,809
19.12.2011, 03:23
pHOMM, в общем, в самом деле, при определении адреса S[x], собственно, просто вычисляется адрес относительно базового адреса Pointer(S). Я попытался выполнить вот такой код:
Delphi
1
2
3
4
5
6
var
  S : String;
begin
  S := '';
  ShowMessage(Format('%p', [ @S[10] ]));
end;
Ошибок не произошло и программа выдала сообщение с текстом: '00000009'. Т. е., был взят базовый адрес Integer(S) = 0 и относительно него с учётом смещения компилятор вычислил окончательный адрес: Integer(S) + (10 - 1) * SizeOf(Char) = 0 + 9 * 1 = 9. Здесь (10 - 1) - для учёта особенности адресации элементов строки.
---
Вывод, значит, такой: при передаче ссылки на данные строки, в качестве параметра в подпрограмму, в любых ситуациях можно использовать любую форму: такую: S[1] или такую: Pointer(S)^. S[1] - так компактнее.
2
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
19.12.2011, 03:23
Помогаю со студенческими работами здесь

Я сделал программу по переносу из записи в типизированный файл, но процедура выдает ошибку.
Вот программа.Выдает вот эту ошибку' Введите артикул детали( d.art:=stringgrid1.Cells) is not a valid integer value'. begin ...

Записать в типизированный файл массив содержащий в себе динамические списки
Доброго времени суток, написал программу, что то типа словаря. Хотелось бы реализовать возможность хранить данные на диске в типизированном...

Дан типизированный файл целых чисел. Переписать содержимое файла в новый типизированный файл
Дан типизированный файл целых чисел. Переписать содержимое файла в новый типизированный файл целых чисел, изменяя порядок ...

Создать типизированный файл из записей, включающих данные о республиках
Создать типизированный файл из записей, включающих данные о республиках. Организовать работу с файлами. Напечатать список республик...

Ввести из текстового файла данные для массива структур, записать их в типизированный файл
type TStudent=record FIO:string;//Поле Ф.И.О. Ngrup:Integer;//Поле номера группы yspev:array of Word;//поле массива...


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

Или воспользуйтесь поиском по форуму:
14
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru