Форум по Delphi программированию

Delphi Sources



Вернуться   Форум по Delphi программированию > Все о Delphi > Файловая система
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 23.04.2008, 12:23
Аватар для KOOL
KOOL KOOL вне форума
Активный
 
Регистрация: 06.01.2008
Адрес: Рязань
Сообщения: 306
Версия Delphi: 2009
Репутация: 6150
По умолчанию StringList в файл

Люди, подскажите плиз, как сохранить TStringList в составе record в файл? У меня сохраняется указатель вместо содержимого
Ответить с цитированием
  #2  
Старый 23.04.2008, 12:52
AlexSku AlexSku вне форума
Специалист
 
Регистрация: 07.05.2007
Адрес: Москва
Сообщения: 884
Репутация: 21699
По умолчанию

Не понял на счёт record'а, но строки сохранить можно так:
Код:
procedure TForm1.Button1Click(Sender: TObject);
var
  SL1: TStringList;
begin
  SL1:= TStringList.Create;
  SL1.AddStrings(ListBox1.Items); // в ListBox'е был текст
  SL1.SaveToFile('mylist.txt');
  SL1.Free;
end;
Ответить с цитированием
  #3  
Старый 24.04.2008, 14:11
Аватар для KOOL
KOOL KOOL вне форума
Активный
 
Регистрация: 06.01.2008
Адрес: Рязань
Сообщения: 306
Версия Delphi: 2009
Репутация: 6150
По умолчанию

в составе record это типа так:
Код:
type MyFile=record
         val1:integer;
         val2:string[20];
         StrList:TStringList
       end;
//а затем
procedure Save(FileName : string);
var OutF : file of MyFile;
begin
...
end;
все сохраняется нормально, кроме StringList
Ответить с цитированием
  #4  
Старый 24.04.2008, 14:18
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,004
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Цитата:
Сообщение от KOOL
в составе record это типа так:
Код:
type MyFile=record
         val1:integer;
         val2:string[20];
         StrList:TStringList
       end;
//а затем
procedure Save(FileName : string);
var OutF : file of MyFile;
begin
...
end;
все сохраняется нормально, кроме StringList

Естественно, у тебя таким образом сохраняется указатель.
И подругому тут ничего не сделаешь.
Варианты решения:
1. В записи хранить String, а для работы в StringList пихать его в StringList.Textэ
2. Отказаться от File Of и писать через TFileStream. В этом случае у тебя полный контроль над тем как и что ты сохраняешь.

Все дело в том, что File Of работает с записями фиксированной длинны, а у тебя содержимое StringList потенциально может быть различной длинны.

Если есть вопросы - wellcome.
Ответить с цитированием
  #5  
Старый 28.04.2008, 19:10
Аватар для KOOL
KOOL KOOL вне форума
Активный
 
Регистрация: 06.01.2008
Адрес: Рязань
Сообщения: 306
Версия Delphi: 2009
Репутация: 6150
По умолчанию

1 способ не подходит...а вот второй как раз да. Тока как потоки юзать?
Ответить с цитированием
  #6  
Старый 28.04.2008, 19:51
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,004
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Цитата:
Сообщение от KOOL
1 способ не подходит...а вот второй как раз да. Тока как потоки юзать?

Код:
procedure SaveToFile(AData : MyFile);
var
  Stream : TFileStream;
  StrLen : Integer;
  SLStr : String;
begin
  Stream := TFileStream.Create('MyFile.dat',fmCreate);
  Try
    Stream.WriteBuffer(AData.val1,SizeOf(Integer));
    StrLen := Length(AData.va2);
    Stream.WriteBuffer(StrLen,SizeOf(Integer));
    Stream.WriteBuffer(AData.val2[1],StrLen);
    SLStr := AData.StrList.Text;
    StrLen := Length(SLStr);
    Stream.WriteBuffer(StrLen,SizeOf(Integer));
    Stream.WriteBuffer(SLStr[1],StrLen);
  Finally
    Stream.Free;
  End;
end;

procedure LoadFromFile(var AData : MyData); // запись должна быть создана, в т.ч. и StringList в ней.
var
  Stream : TFileStream;
  StrLen : Integer;
  SLStr : String;
begin
  Stream := TFileStream.Create('MyFile.dat',fmRead);
  Try
    Stream.ReadBuffer(AData.val1,SizeOf(Integer));
    Stream.ReadBuffer(StrLen,SizeOf(Integer));
    Stream.ReadBuffer(AData.val2[1],StrLen);
    Stream.ReadBuffer(StrLen,SizeOf(Integer));
    SetLength(SLStr,StrLen);
    Stream.ReadBuffer(SLStr[1],StrLen);
    AData.Text := SLStr;
  Finally
    Stream.Free;
  End;
end;

Фокус тут только в одном - перед записью строки мы пишем в поток ее реальную длинну. При обратном чтении сначала читаем длинну и для SNSI строк выделяем память под данные (SetLength). Это связанно с тем, что мы не можем ограничить, например, StringList при вызове его метода LoadFromStream каким-либо кол-вом вычитываемой информации. Вот и приходится таким маневром обходить это ограничение. Впрочем, с PASCAL-строками фактически таже история. Нам надо знать сколько актуальная длина для операций сохранения/чтения в/из потока.
Ответить с цитированием
  #7  
Старый 29.04.2008, 14:09
Аватар для KOOL
KOOL KOOL вне форума
Активный
 
Регистрация: 06.01.2008
Адрес: Рязань
Сообщения: 306
Версия Delphi: 2009
Репутация: 6150
По умолчанию

Так...буду разбираться...Спасибо!
А если мне надо записать в файл массив или record с массивами, то как мне это все считать потом(да и записать правильно)?
Ответить с цитированием
  #8  
Старый 29.04.2008, 16:13
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,004
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Если у тебя массив таких элементов, то сначала пишешь их кол-во (что бы потом правильно считать), а потом последовательно сами элементы. Читаешь, соотв., сначала кол-во, потом циклом от 1 до N элементы.
Ответить с цитированием
  #9  
Старый 30.04.2008, 13:56
Аватар для KOOL
KOOL KOOL вне форума
Активный
 
Регистрация: 06.01.2008
Адрес: Рязань
Сообщения: 306
Версия Delphi: 2009
Репутация: 6150
По умолчанию

Вроде разобрался, но при чтении все время вылетает Stream Read Error. При пошаговом выполнении я заметил, что считанная длина строки обычно по модулю больше миллиона... Что у меня не так?
Код:
//сохранение
Str := Test.TestSubject;
StrLen := Length(Str);
Stream.WriteBuffer(StrLen, SizeOf(Integer));
Stream.WriteBuffer(Str[1], StrLen);
...
//загрузка
Stream.ReadBuffer(StrLen, SizeOf(Integer));//StrLen здесь равен -398.....
SetLength(Test.TestSubject, StrLen);
Stream.ReadBuffer(Test.TestSubject[1], StrLen);//здесь вылетает ошибка
...
Ответить с цитированием
  #10  
Старый 30.04.2008, 17:15
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,004
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

На первый взгляд все равильно.
Выложи куда-нить полный код.
Ответить с цитированием
  #11  
Старый 30.04.2008, 21:46
Аватар для KOOL
KOOL KOOL вне форума
Активный
 
Регистрация: 06.01.2008
Адрес: Рязань
Сообщения: 306
Версия Delphi: 2009
Репутация: 6150
По умолчанию

Код в аттаче. Урезал все, что не относится к сохранению/загрузке
Вложения
Тип файла: txt TestEditor.txt (11.4 Кбайт, 23 просмотров)
Ответить с цитированием
  #12  
Старый 30.04.2008, 21:59
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,004
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

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

Ну и втретьих - общее замечание. Я бы все-таки сделал все классами и у них бы понаписал методов SaveTostream и LoadFromStream, а в основной программе просто дергал бы метод "верхнего" класса, который в свою очередь дергал бы все, что ниже лежит. а хранение организовал бы с помощью TObjectList.
Ответить с цитированием
  #13  
Старый 01.05.2008, 11:26
voron_paa voron_paa вне форума
Прохожий
 
Регистрация: 26.01.2008
Сообщения: 49
Репутация: 10
По умолчанию

Цитата:
Сообщение от lmikle
во-первых. а кто будет аллокировать память? ты используешь динамические массивы - так его длинну надо определить после того, как ты считываешь кол-во записей.
во-вторых, для кол-ва записей заведи себе отдельную переменную.

Ну и втретьих - общее замечание. Я бы все-таки сделал все классами и у них бы понаписал методов SaveTostream и LoadFromStream, а в основной программе просто дергал бы метод "верхнего" класса, который в свою очередь дергал бы все, что ниже лежит. а хранение организовал бы с помощью TObjectList.

В свою очередь я бы предложил создать потомка класса TList в котором уже всё это есть надо тока чуточку дописать и всё...
А хранить всё в items. А для записи создать свой класс и пихать их Items... И без массивов...
Ответить с цитированием
  #14  
Старый 05.05.2008, 14:41
Аватар для KOOL
KOOL KOOL вне форума
Активный
 
Регистрация: 06.01.2008
Адрес: Рязань
Сообщения: 306
Версия Delphi: 2009
Репутация: 6150
По умолчанию

Все, я разобрался. Я кое-где в Sizeof вместо byte поставил Cardinal, а так все было правильно. Спасибо за помощь
Ответить с цитированием
  #15  
Старый 05.05.2008, 15:18
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,004
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Цитата:
Сообщение от voron_paa
В свою очередь я бы предложил создать потомка класса TList в котором уже всё это есть надо тока чуточку дописать и всё...
А хранить всё в items. А для записи создать свой класс и пихать их Items... И без массивов...

Собственно, TObjectList и есть TList с 2мя "вкусностями":
1. Он хранит ссылки на объекты, а не нетипизированные указатели.
2. Он может быть владельцем объектов, т.е. не нужно заботиться о вызове деструктора при удалении объектов из него.
а в остальном это и есть обычный TList.
Ответить с цитированием
Ответ


Delphi Sources

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 00:19.


 

Сайт

Форум

FAQ

RSS лента

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2023

ВКонтакте   Facebook   Twitter