Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.141.31.240] |
|
Сообщ.
#1
,
|
|
|
Здравстсвуйте!
Никак не получается сохранить в файл record, а затем вновь загрузить его! Запись имеет большой размер, состоит из полей разного типа, безразмерных массивов, переменных других типой(определенных) мной. Пробовал очень просто, через поток: var fs: TFileStream; begin if sd.Execute then begin fs:=TFileStream.Create(sd.FileName,fmCreate); fs.WriteBuffer(Project, SizeOf(Project)); fs.Free; end; end; Ну и соответственно загрузка: var fs: TFileStream; begin if not od.Execute then exit; fs:=TFileStream.Create(od.FileName,fmOpenRead); fs.ReadBuffer(Project, fs.Size); fs.Free; end; Ничего не получилось... (( Подскажите как это реализовать? Заранее спасибо! |
Сообщ.
#2
,
|
|
|
Цитата R@RED @ безразмерных массивов, Ну не безразмерных, конечно, а динамических Поэтому и не получается. Самое простое - сделай не запись, а потомка TComponent. Все, что нужно сохранять, объяви как published property. И потом просто используй поток. |
Сообщ.
#3
,
|
|
|
Цитата R@RED @ Показывать надо не только краешек, ниже спускать, как у доктора, иначе тебе никто не поможет. Что за Project? Подскажите как это реализовать? Заранее спасибо! |
Сообщ.
#4
,
|
|
|
TSampleRec=record Text: String; Num: Integer; end; i: integer; sr: TSampleRec; fs: TFileStream; begin sr.Text := 'test text'; sr.Num := 19; // Пишем fs := TFileStream.Create('c:\temp\file.tst', fmCreate); try i := Length(sr.Text); fs.Write(i,4); fs.Write(sr.Text[1],Length(sr.Text)); fs.Write(sr.Num,4); finally fs.Free; end; // Читаем fs := TFileStream.Create('c:\temp\file.tst', fmOpenRead); try fs.Read(i,4); SetLength(sr.Text,i); fs.Read(sr.Text[1],i); fs.Read(sr.Num,4); finally fs.Free; end; |
Сообщ.
#5
,
|
|
|
Цитата Romkin @ Все, что нужно сохранять, объяви как published property. И потом просто используй поток. Угу, а потом когда в след версии измениться логика чтения/сохранения RTTI свойств, попробуй всю эту байду прочитать |
Сообщ.
#6
,
|
|
|
Если косяк именно из-за дин. массивов, то почему бы в структуре не хранить число элементов и написть свою процедуру считывания данных, а не потоком ?
|
Сообщ.
#7
,
|
|
|
Цитата Демо @ fs.Write(i,4); Опять Демо новичков плохому учит! |
Сообщ.
#8
,
|
|
|
Цитата --Ins-- @ Опять Демо новичков плохому учит! Это почему это? -)) |
Сообщ.
#9
,
|
|
|
Цитата Демо @ Это почему это? -)) http://ru.wikipedia.org/wiki/Магическое_число_(программирование) - см. "Плохая практика программирования" Про SizeOf слышал? |
Сообщ.
#10
,
|
|
|
Цитата --Ins-- @ Про SizeOf слышал? Увы, переносимости в любом случае не будет. Как раз в этом случае integer не может менять длину. Оно ОБЯЗАНО быть 4 байта. Иначе нет смысла хранить данные таким образом. Добавлено PS. Википедия - весьма спорный аргумент. Я бы сказал, что ей доверять нельзя ВООБЩЕ. |
Сообщ.
#11
,
|
|
|
Цитата Демо @ Увы, переносимости в любом случае не будет. Уверен? А чем тогда отличаются фундаментальные типы от общих? А конкретно, Longint от Integer? Добавлено Цитата Демо @ Википедия - весьма спорный аргумент. Согласен, но не в данном случае |
Сообщ.
#12
,
|
|
|
Цитата --Ins-- @ Уверен? А чем тогда отличаются фундаментальные типы от общих? А конкретно, Longint от Integer? Поможет ли SizeOf в случае переноса данных с одного ПК на другой, если на одном целый тип будет занимать 8 байт, а на другом 4? Думаю, что нет. Поэтому в этом случае неприменим SizeOf. |
Сообщ.
#13
,
|
|
|
Цитата Демо @ Поможет ли SizeOf в случае переноса данных с одного ПК на другой, если на одном целый тип будет занимать 8 байт, а на другом 4? Думаю, что нет. Поэтому в этом случае неприменим SizeOf. Тэкс, ты вопроса про общие и фундаментальные типы не понял... Что ж, спрошу без намеков... SizeOf(Longint) применим? |
Сообщ.
#14
,
|
|
|
Цитата --Ins-- @ Тэкс, ты вопроса про общие и фундаментальные типы не понял... Что ж, спрошу без намеков... SizeOf(Longint) применим? Longint применим;) Добавлено В смысле Sizeof(Longint)... |
Сообщ.
#15
,
|
|
|
Демо, ну дык чего ты мне доказываешь Видишь, и SizeOf применим, и переносимость, и нет "магических чисел" в коде
|
Сообщ.
#16
,
|
|
|
Цитата --Ins-- @ Видишь, и SizeOf применим Ты скажи мне, фундаментальный тип всегда останется неизменного размера? Уверен в том? |
Сообщ.
#17
,
|
|
|
Write заменить на WriteBuffer а по поводу SizeOf есть вот такой вопросик:
SizeOf(Char) = ? |
Сообщ.
#18
,
|
|
|
Хых, страшно рад, что мой вопрос вызвал такой оживленный спор... =)
Цитата Rouse_ @ TSampleRec=record Text: String; Num: Integer; end; i: integer; sr: TSampleRec; fs: TFileStream; begin sr.Text := 'test text'; sr.Num := 19; // Пишем fs := TFileStream.Create('c:\temp\file.tst', fmCreate); try i := Length(sr.Text); fs.Write(i,4); fs.Write(sr.Text[1],Length(sr.Text)); fs.Write(sr.Num,4); finally fs.Free; end; // Читаем fs := TFileStream.Create('c:\temp\file.tst', fmOpenRead); try fs.Read(i,4); SetLength(sr.Text,i); fs.Read(sr.Text[1],i); fs.Read(sr.Num,4); finally fs.Free; end; Rouse, если бы все было так просто, я бы и вопрос не задавал! ) Такая мысль мне и самому приходила. Согласен, что так рекорд успешно запишется, но если учесть, что в нем несколько десятков полей, многие из которых также являются записями, которые также содержать большое количество полей и динамических массивов... К тому же размер файла существенно возрастет, если перед каждой переменной записывать ее размер, да и скорость будет не совсем приемлимой... Я уж не говорю о том, что я просто запарюсь печетать! =\ Может есть другой способ? |
Сообщ.
#19
,
|
|
|
Ins! Rouse! Блин, ну создали бы что-ли отдельную ветку "Филосифия Delphi"! )) А у меня сейчас есть реальный вопрос и совсем не много времени! Плиз, ребята, помогите разобраться!
|
Сообщ.
#20
,
|
|
|
R@RED приведи пример твоей записи попробую помочь ...
Сообщения были разделены в тему "Фундаментальные и общие типы данных" |
Сообщ.
#21
,
|
|
|
хм нифигасе нафлудили, и кто?, люди облаченные властью и знаниями
а про то что помочь топикстартеру забыли? а проблема имхо на поверхности! R@RED type TProject =record num:word; doc:array[1..128] of char; end .. var Project:TProject; ... WriteBuffer(Project, SizeOf(Project)); сработает! а вот type TProject =record num:word; doc:Pchar; end .. var Project:TProject; ... WriteBuffer(Project, SizeOf(Project)); нет! а почему? догадался? ЗЫ примерчик офтопа как то раз пришел один ко мне на работе и говорит типа ты че лох говориш что песенки занимают примерно 1метр/минута, вот у меня на дискете 400 песен и еще место осталось. и как вы думаете что было на дискете? правильно... 400 ярлыков, у дома у него все работало не используй указательные типы (pchar это указатель на на массив символов, имеет размер sizeof(pointer), а данные находятся в другой области памяти) |
Сообщ.
#22
,
|
|
|
Цитата andrew.virus @ приведи пример твоей записи попробую помочь ... Ок, по определенным причинам не могу привести конкретно свой рекорд, но приведу подобный, если удасться сохранить его, то и проблема будет решена: type TRecType1 = (rtRTV1, rtRTV2); type TRecType2 = set of (rttRTV1, rttRTV2); type TSubRec = record str1 : string; str2 : ShortString; int1 : integer; int2 : LongInt; _type : TRecType1; _type1 : TRecType2; mass1 : array of string; mass2 : array of integer; bool1 : boolean; end; type TProject = record mass1 : array of TSubRec; str1 : string; int1 : LongInt; int2 : integer; bool1 : boolean; end; Только необходимо учитывать, что полей и типов гораздо больше, так что способ Демо не подходит. Есть идеи? =) |
Сообщ.
#23
,
|
|
|
R@REDмой пост выше читал?
sizeof(mass1) =4 !!! как думаеш почему? кстати string тоже указатель фиксированный только ShortString Добавлено в твоем примере type TRecType1 = (rtRTV1, rtRTV2); type TRecType2 = set of (rttRTV1, rttRTV2); type TSubRec = record str1 : string; str2 : ShortString; int1 : integer; int2 : LongInt; _type : TRecType1; _type1 : TRecType2; mass1 : array of string; mass2 : array of integer; bool1 : boolean; end; type TProject = record mass1 : array of TSubRec; str1 : string; int1 : LongInt; int2 : integer; bool1 : boolean; end; это ошибки |
Сообщ.
#24
,
|
|
|
Цитата Virtuals @ sizeof(mass1) =4 !!! как думаеш почему? Почему же? Цитата Virtuals @ это ошибки Что значит ошибки, если мне необходимо использование именно этих типов? Если string на какой то подобный строковой тип я еще смогу заменить, то как например я должен обходиться без динамических массивов? Извини, если чего-то не понял, буду рад, если приведешь правильный пример записи. |
Сообщ.
#25
,
|
|
|
R@RED
Универсального решения для сохранения структур в файл нет. Принцип понятен, остальное - кодирование. Т.е. каждую структуру нужно обрабатывать по-своему. |
Сообщ.
#26
,
|
|
|
Цитата Демо @ каждую структуру нужно обрабатывать по-своему. Цитата R@RED @ Согласен, что так рекорд успешно запишется, но если учесть, что в нем несколько десятков полей, многие из которых также являются записями, которые также содержать большое количество полей и динамических массивов... К тому же размер файла существенно возрастет, если перед каждой переменной записывать ее размер, да и скорость будет не совсем приемлимой... Я правильно понял, что в моем случае обрабатывать структуры по одтельности - это единственный путь и ни смотря на все минусы альтернативного решения нет? =( |
Сообщ.
#27
,
|
|
|
Цитата R@RED @ Я правильно понял, что в моем случае обрабатывать структуры по одтельности - это единственный путь и ни смотря на все минусы альтернативного решения нет? =( Именно так. А что, у тебя их так много? Если структуры - своеобразные наследники друг друга, то альтернативный вариант - создание классов наследников, которые умеют писать себя в поток. Это поможет упростить код и умегьшить его объём. |
Сообщ.
#28
,
|
|
|
Цитата Демо @ Это уже интереснее... А как можно реализовать умение "писать себя в поток", если опять же не пробегать все элементы по отдельности? создание классов наследников, которые умеют писать себя в поток. Это поможет упростить код и умегьшить его объём. |
Сообщ.
#29
,
|
|
|
Цитата R@RED @ А как можно реализовать умение "писать себя в поток", если опять же не пробегать все элементы по отдельности? Писать каждый элемент в любом случае придётся. Упрощение возможно лишь в случае наследования когда каждый наследник лишь добавляет новые поля для записи, а предок уже умеет работать с остальными полями. |
Сообщ.
#30
,
|
|
|
Оуу... Ясно! Что ж, видимо все таки придеться писать все по очереди... =\ Ладно, спасибо за ответы, буду рад если у кого то еще появятся какие то идеи.
|
Сообщ.
#31
,
|
|
|
R@RED
Цитата Цитата (Virtuals @ Сегодня, 08:33) sizeof(mass1) =4 !!! как думаеш почему? Почему же? потому что это указатель pointer (аналог ярлыка в виндах, типа написано на бумажке "машина стоит за углом") тоесть самих данных в переменной нет, она ссылается на область памяти где хранятся сами данные. Цитата то как например я должен обходиться без динамических массивов? а как вы узнаете размер вашего массива? чтоб не вызвать AV если для строк еще боле менее узнать размер (ну напр по терминирующему #0) то как узнать размер структуры mass2 : array of integer; ? в от с mass2 : array of string; вообще грабли, вот разберем этот пример mass2 : array of string; есть не что иное как указатель на область памяти, где хранится массив, произвольной длинны, указателей, которые ссылаются на области памяти, произвольной длинны, где данные, теоритически, оканчиваются на #0 вот мы и пришли к тому что "сложные" структуры, (тоесть такие где используются переменные, с неизвестным размером") лучше сохранять в какую либо БД, а какая это БД будет вам решать, но учтите что в ней каждый раз должно сохранятся неизвестное количество полей с произвольной длинной ЗЫ смотрите в сторону XML |
Сообщ.
#32
,
|
|
|
Цитата Virtuals @ Потом уже догадался )потому что это указатель pointer Цитата Virtuals @ Ясненько! )есть не что иное как указатель на область памяти, где хранится, массив, произвольной длинны, указателей, которые ссылаются на области памяти, произвольной длинны, где данные, теоритически, оканчиваются на #0 Цитата Virtuals @ Не катит, не спрашивайте почему, просто БД в этом случае мне не подходит...вот мы и пришли к тому что "сложные" структуры, (тоесть такие где используются переменные, с неизвестным размером") лучше сохранять в какую либо БД Ладно, я уже почти смирился со способом предложенным Демо. )) Всем спасибо, вопрос решен. |
Сообщ.
#33
,
|
|
|
R@RED
Есть один вариант. Но насколько он сложен(или прост) не скажу, пока не попробую реализовать сам. Подумаю немного-) |
Сообщ.
#34
,
|
|
|
Буду очень рад свежей идее! =)
|
Сообщ.
#35
,
|
|
|
Я тебе уже дал идею в #2. То, что говорит Rouse по этому поводу - фигня. Но если уж хочется подстраховаться, то можно писать файл в текстовом виде, там уж разночтений не будет.
|
Сообщ.
#36
,
|
|
|
Пример заготовки для копирования в TStream любой структуры:
Необходимо описание самой структуры (packed record) и строка с описанием типов полей: один символ - одно поле в структуре. Это лишь заготовка, необходимо тестировать в различных условиях. unit uTypes; interface uses Classes; type tRec=packed record fString: String; fInt: Integer; fInt64: Int64; fBoolean: Boolean; end; function GetRec(PointerToRecord: Pointer; RecordSH: String; Stream: TStream): Integer; function PutRec(PointerToRecord: Pointer; RecordSH: String; Stream: TStream): Integer; const RecSh='si6b'; implementation function GetRec(PointerToRecord: Pointer; RecordSH: String; Stream: TStream): Integer; var p: Pointer; c: Char; i: integer; Len: Integer; begin Result := 0; p := PointerToRecord; for i := 1 to Length(RecordSH) do begin c := UpCase(RecordSH[i]); case c of 'S': begin Stream.ReadBuffer(Len,SizeOf(Integer)); SetLength(PString(p)^,Len); Stream.ReadBuffer(PString(p)^[1],Len); p := Pointer(Integer(p)+SizeOf(String)); Result := Result + SizeOf(String)+Len; end; 'I': begin Stream.ReadBuffer(PInteger(p)^,SizeOf(Integer)); p := Pointer(Integer(p)+SizeOf(Integer)); Result := Result + SizeOf(Integer); end; '6': begin Stream.ReadBuffer(PInt64(p)^,SizeOf(Int64)); p := Pointer(Integer(p)+SizeOf(Int64)); Result := Result + SizeOf(Int64); end; 'B': begin Stream.ReadBuffer(PBoolean(p)^,SizeOf(Boolean)); p := Pointer(Integer(p)+SizeOf(Boolean)); Result := Result + SizeOf(Boolean); end; end; end; end; function PutRec(PointerToRecord: Pointer; RecordSH: String; Stream: TStream): Integer; var p: Pointer; c: Char; i: integer; Len: Integer; begin Result := 0; p := PointerToRecord; for i := 1 to Length(RecordSH) do begin c := UpCase(RecordSH[i]); case c of 'S': begin Len := Length(PString(p)^); Stream.WriteBuffer(Len,SizeOf(Integer)); Stream.WriteBuffer(PString(p)^[1],Len); p := Pointer(Integer(p)+SizeOf(String)); Result := Result + SizeOf(String)+Len; end; 'I': begin Stream.WriteBuffer(PInteger(p)^,SizeOf(Integer)); p := Pointer(Integer(p)+SizeOf(Integer)); Result := Result + SizeOf(Integer); end; '6': begin Stream.WriteBuffer(PInt64(p)^,SizeOf(Int64)); p := Pointer(Integer(p)+SizeOf(Int64)); Result := Result + SizeOf(Int64); end; 'B': begin Stream.WriteBuffer(PBoolean(p)^,SizeOf(Boolean)); p := Pointer(Integer(p)+SizeOf(Boolean)); Result := Result + SizeOf(Boolean); end; end; end; end; end. Пример использования: procedure TForm1.Button1Click(Sender: TObject); type pRec=^TRec; var fs: TFileStream; tr: PRec; tr1: TRec; begin New(tr); tr^.fString := 'ПРоверка записи строки в файл'; tr^.fInt := 1; tr^.fInt64 := 2; tr^.fBoolean := True; fs := TFileStream.Create('c:\test.dat', fmCreate); try uTypes.PutRec(tr,RecSH,fs); finally fs.Free; Dispose(tr); end; fs := TFileStream.Create('c:\test.dat', fmOpenRead); try uTypes.GetRec(@tr1,RecSH,fs); finally fs.Free; end; ShowMessage(tr1.fString+'/'+ IntToStr(tr1.fInt)+'/'+ IntToStr(tr1.fInt64)+'/'+ IntToStr(Integer(tr1.fBoolean))); end; |