|
#1
|
||||
|
||||
StringList в файл
Люди, подскажите плиз, как сохранить TStringList в составе record в файл? У меня сохраняется указатель вместо содержимого
|
#2
|
|||
|
|||
Не понял на счёт 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
|
||||
|
||||
в составе record это типа так:
Код:
type MyFile=record val1:integer; val2:string[20]; StrList:TStringList end; //а затем procedure Save(FileName : string); var OutF : file of MyFile; begin ... end; |
#4
|
|||
|
|||
Цитата:
Естественно, у тебя таким образом сохраняется указатель. И подругому тут ничего не сделаешь. Варианты решения: 1. В записи хранить String, а для работы в StringList пихать его в StringList.Textэ 2. Отказаться от File Of и писать через TFileStream. В этом случае у тебя полный контроль над тем как и что ты сохраняешь. Все дело в том, что File Of работает с записями фиксированной длинны, а у тебя содержимое StringList потенциально может быть различной длинны. Если есть вопросы - wellcome. |
#5
|
||||
|
||||
1 способ не подходит...а вот второй как раз да. Тока как потоки юзать?
|
#6
|
|||
|
|||
Цитата:
Код:
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
|
||||
|
||||
Так...буду разбираться...Спасибо!
А если мне надо записать в файл массив или record с массивами, то как мне это все считать потом(да и записать правильно)? |
#8
|
|||
|
|||
Если у тебя массив таких элементов, то сначала пишешь их кол-во (что бы потом правильно считать), а потом последовательно сами элементы. Читаешь, соотв., сначала кол-во, потом циклом от 1 до N элементы.
|
#9
|
||||
|
||||
Вроде разобрался, но при чтении все время вылетает 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
|
|||
|
|||
На первый взгляд все равильно.
Выложи куда-нить полный код. |
#11
|
||||
|
||||
Код в аттаче. Урезал все, что не относится к сохранению/загрузке
|
#12
|
|||
|
|||
во-первых. а кто будет аллокировать память? ты используешь динамические массивы - так его длинну надо определить после того, как ты считываешь кол-во записей.
во-вторых, для кол-ва записей заведи себе отдельную переменную. Ну и втретьих - общее замечание. Я бы все-таки сделал все классами и у них бы понаписал методов SaveTostream и LoadFromStream, а в основной программе просто дергал бы метод "верхнего" класса, который в свою очередь дергал бы все, что ниже лежит. а хранение организовал бы с помощью TObjectList. |
#13
|
|||
|
|||
Цитата:
В свою очередь я бы предложил создать потомка класса TList в котором уже всё это есть надо тока чуточку дописать и всё... А хранить всё в items. А для записи создать свой класс и пихать их Items... И без массивов... |
#14
|
||||
|
||||
Все, я разобрался. Я кое-где в Sizeof вместо byte поставил Cardinal, а так все было правильно. Спасибо за помощь
|
#15
|
|||
|
|||
Цитата:
Собственно, TObjectList и есть TList с 2мя "вкусностями": 1. Он хранит ссылки на объекты, а не нетипизированные указатели. 2. Он может быть владельцем объектов, т.е. не нужно заботиться о вызове деструктора при удалении объектов из него. а в остальном это и есть обычный TList. |