На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! ПРАВИЛА РАЗДЕЛА · FAQ раздела Delphi · Книги по Delphi
Пожалуйста, выделяйте текст программы тегом [сode=pas] ... [/сode]. Для этого используйте кнопку [code=pas] в форме ответа или комбобокс, если нужно вставить код на языке, отличном от Дельфи/Паскаля.
Следующие вопросы задаются очень часто, подробно разобраны в FAQ и, поэтому, будут безжалостно удаляться:
1. Преобразовать переменную типа String в тип PChar (PAnsiChar)
2. Как "свернуть" программу в трей.
3. Как "скрыться" от Ctrl + Alt + Del (заблокировать их и т.п.)
4. Как прочитать список файлов, поддиректорий в директории?
5. Как запустить программу/файл?
... (продолжение следует) ...

Вопросы, подробно описанные во встроенной справочной системе Delphi, не несут полезной тематической нагрузки, поэтому будут удаляться.
Запрещается создавать темы с просьбой выполнить какую-то работу за автора темы. Форум является средством общения и общего поиска решения. Вашу работу за Вас никто выполнять не будет.


Внимание
Попытки открытия обсуждений реализации вредоносного ПО, включая различные интерпретации спам-ботов, наказывается предупреждением на 30 дней.
Повторная попытка - 60 дней. Последующие попытки бан.
Мат в разделе - бан на три месяца...
Модераторы: jack128, D[u]fa, Shaggy, Rouse_
  
> Сохранение записи сложной структры в файл
    Здравстсвуйте!

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

    Пробовал очень просто, через поток:
    ExpandedWrap disabled
      var
        fs: TFileStream;
      begin
        if sd.Execute then begin
          fs:=TFileStream.Create(sd.FileName,fmCreate);
          fs.WriteBuffer(Project, SizeOf(Project));
          fs.Free;
        end;
      end;

    Ну и соответственно загрузка:
    ExpandedWrap disabled
      var
        fs: TFileStream;
      begin
        if not od.Execute then exit;
       
        fs:=TFileStream.Create(od.FileName,fmOpenRead);
        fs.ReadBuffer(Project, fs.Size);
        fs.Free;
      end;

    Ничего не получилось... (( Подскажите как это реализовать? Заранее спасибо!
    Сообщение отредактировано: R@RED -
      Цитата R@RED @
      безразмерных массивов,

      Ну не безразмерных, конечно, а динамических :)
      Поэтому и не получается. Самое простое - сделай не запись, а потомка TComponent. Все, что нужно сохранять, объяви как published property. И потом просто используй поток.
        Цитата R@RED @
        Подскажите как это реализовать? Заранее спасибо!
        Показывать надо не только краешек, ниже спускать, как у доктора, иначе тебе никто не поможет. Что за Project?
          ExpandedWrap disabled
              TSampleRec=record
                Text: String;
                Num: Integer;
              end;


          ExpandedWrap disabled
              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;
            Цитата Romkin @
            Все, что нужно сохранять, объяви как published property. И потом просто используй поток.

            Угу, а потом когда в след версии измениться логика чтения/сохранения RTTI свойств, попробуй всю эту байду прочитать :)
              Если косяк именно из-за дин. массивов, то почему бы в структуре не хранить число элементов и написть свою процедуру считывания данных, а не потоком ?
                Цитата Демо @
                fs.Write(i,4);


                Опять Демо новичков плохому учит! :D
                  Цитата --Ins-- @
                  Опять Демо новичков плохому учит!


                  :D

                  Это почему это? -))
                    Цитата Демо @
                    Это почему это? -))


                    http://ru.wikipedia.org/wiki/Магическое_число_(программирование) - см. "Плохая практика программирования"
                    Про SizeOf слышал? ;)
                      Цитата --Ins-- @
                      Про SizeOf слышал?


                      Увы, переносимости в любом случае не будет.
                      Как раз в этом случае integer не может менять длину. Оно ОБЯЗАНО быть 4 байта. Иначе нет смысла хранить данные таким образом.

                      Добавлено
                      PS.
                      Википедия - весьма спорный аргумент.
                      Я бы сказал, что ей доверять нельзя ВООБЩЕ.
                        Цитата Демо @
                        Увы, переносимости в любом случае не будет.


                        Уверен? А чем тогда отличаются фундаментальные типы от общих? А конкретно, Longint от Integer?

                        Добавлено
                        Цитата Демо @
                        Википедия - весьма спорный аргумент.


                        Согласен, но не в данном случае ;)
                          Цитата --Ins-- @
                          Уверен? А чем тогда отличаются фундаментальные типы от общих? А конкретно, Longint от Integer?


                          Поможет ли SizeOf в случае переноса данных с одного ПК на другой, если на одном целый тип будет занимать 8 байт, а на другом 4?
                          Думаю, что нет. Поэтому в этом случае неприменим SizeOf.
                            Цитата Демо @
                            Поможет ли SizeOf в случае переноса данных с одного ПК на другой, если на одном целый тип будет занимать 8 байт, а на другом 4?
                            Думаю, что нет. Поэтому в этом случае неприменим SizeOf.


                            Тэкс, ты вопроса про общие и фундаментальные типы не понял... Что ж, спрошу без намеков... SizeOf(Longint) применим?
                              Цитата --Ins-- @
                              Тэкс, ты вопроса про общие и фундаментальные типы не понял... Что ж, спрошу без намеков... SizeOf(Longint) применим?


                              Longint применим;)

                              Добавлено
                              В смысле Sizeof(Longint)...
                                Демо, ну дык чего ты мне доказываешь :) Видишь, и SizeOf применим, и переносимость, и нет "магических чисел" в коде
                                  Цитата --Ins-- @
                                  Видишь, и SizeOf применим


                                  Ты скажи мне, фундаментальный тип всегда останется неизменного размера?;) Уверен в том?
                                    Write заменить на WriteBuffer а по поводу SizeOf есть вот такой вопросик:
                                    SizeOf(Char) = ? ;)
                                      Хых, страшно рад, что мой вопрос вызвал такой оживленный спор... =)
                                      Цитата 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, если бы все было так просто, я бы и вопрос не задавал! ) Такая мысль мне и самому приходила. Согласен, что так рекорд успешно запишется, но если учесть, что в нем несколько десятков полей, многие из которых также являются записями, которые также содержать большое количество полей и динамических массивов... К тому же размер файла существенно возрастет, если перед каждой переменной записывать ее размер, да и скорость будет не совсем приемлимой... Я уж не говорю о том, что я просто запарюсь печетать! =\
                                      Может есть другой способ?
                                        Ins! Rouse! Блин, ну создали бы что-ли отдельную ветку "Филосифия Delphi"! )) А у меня сейчас есть реальный вопрос и совсем не много времени! Плиз, ребята, помогите разобраться!
                                          R@RED приведи пример твоей записи попробую помочь ...

                                          Сообщения были разделены в тему "Фундаментальные и общие типы данных"
                                            хм нифигасе нафлудили, и кто?, люди облаченные властью и знаниями :P
                                            а про то что помочь топикстартеру забыли? а проблема имхо на поверхности!
                                            R@RED
                                            ExpandedWrap disabled
                                              type
                                              TProject =record
                                              num:word;
                                              doc:array[1..128] of char;
                                              end
                                              ..
                                              var Project:TProject;
                                              ...
                                              WriteBuffer(Project, SizeOf(Project));

                                            сработает!
                                            а вот
                                            ExpandedWrap disabled
                                              type
                                              TProject =record
                                              num:word;
                                              doc:Pchar;
                                              end
                                              ..
                                              var Project:TProject;
                                              ...
                                              WriteBuffer(Project, SizeOf(Project));

                                            нет! а почему? догадался?

                                            ЗЫ примерчик офтопа
                                            ExpandedWrap disabled
                                              как то раз пришел один ко мне на работе и говорит типа ты че лох говориш что песенки занимают примерно 1метр/минута, вот у меня на дискете 400 песен и еще место осталось. и как вы думаете что было на дискете? правильно... 400 ярлыков, у дома у него все работало


                                            не используй указательные типы (pchar это указатель на на массив символов, имеет размер sizeof(pointer), а данные находятся в другой области памяти) 8-)
                                              Цитата andrew.virus @
                                              приведи пример твоей записи попробую помочь ...

                                              Ок, по определенным причинам не могу привести конкретно свой рекорд, но приведу подобный, если удасться сохранить его, то и проблема будет решена:
                                              ExpandedWrap disabled
                                                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;

                                              Только необходимо учитывать, что полей и типов гораздо больше, так что способ Демо не подходит. Есть идеи? =)
                                              Сообщение отредактировано: R@RED -
                                                R@REDмой пост выше читал?
                                                sizeof(mass1) =4 !!! как думаеш почему?
                                                кстати string тоже указатель :D
                                                фиксированный только 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;
                                                это ошибки
                                                Сообщение отредактировано: Virtuals -
                                                  Цитата Virtuals @
                                                  sizeof(mass1) =4 !!! как думаеш почему?

                                                  Почему же?
                                                  Цитата Virtuals @
                                                  это ошибки

                                                  Что значит ошибки, если мне необходимо использование именно этих типов? Если string на какой то подобный строковой тип я еще смогу заменить, то как например я должен обходиться без динамических массивов?
                                                  Извини, если чего-то не понял, буду рад, если приведешь правильный пример записи.
                                                    R@RED
                                                    Универсального решения для сохранения структур в файл нет.
                                                    Принцип понятен, остальное - кодирование.
                                                    Т.е. каждую структуру нужно обрабатывать по-своему.
                                                      Цитата Демо @
                                                      каждую структуру нужно обрабатывать по-своему.

                                                      Цитата R@RED @
                                                      Согласен, что так рекорд успешно запишется, но если учесть, что в нем несколько десятков полей, многие из которых также являются записями, которые также содержать большое количество полей и динамических массивов... К тому же размер файла существенно возрастет, если перед каждой переменной записывать ее размер, да и скорость будет не совсем приемлимой...

                                                      Я правильно понял, что в моем случае обрабатывать структуры по одтельности - это единственный путь и ни смотря на все минусы альтернативного решения нет? =(
                                                        Цитата R@RED @
                                                        Я правильно понял, что в моем случае обрабатывать структуры по одтельности - это единственный путь и ни смотря на все минусы альтернативного решения нет? =(


                                                        Именно так.
                                                        А что, у тебя их так много?

                                                        Если структуры - своеобразные наследники друг друга, то альтернативный вариант - создание классов наследников, которые умеют писать себя в поток. Это поможет упростить код и умегьшить его объём.
                                                          Цитата Демо @
                                                          создание классов наследников, которые умеют писать себя в поток. Это поможет упростить код и умегьшить его объём.
                                                          Это уже интереснее... А как можно реализовать умение "писать себя в поток", если опять же не пробегать все элементы по отдельности?
                                                            Цитата R@RED @
                                                            А как можно реализовать умение "писать себя в поток", если опять же не пробегать все элементы по отдельности?


                                                            Писать каждый элемент в любом случае придётся. Упрощение возможно лишь в случае наследования когда каждый наследник лишь добавляет новые поля для записи, а предок уже умеет работать с остальными полями.
                                                            Сообщение отредактировано: Демо -
                                                              Оуу... Ясно! Что ж, видимо все таки придеться писать все по очереди... =\ Ладно, спасибо за ответы, буду рад если у кого то еще появятся какие то идеи.
                                                                R@RED
                                                                Цитата
                                                                Цитата (Virtuals @ Сегодня, 08:33)
                                                                sizeof(mass1) =4 !!! как думаеш почему?

                                                                Почему же?

                                                                потому что это указатель pointer (аналог ярлыка в виндах, типа написано на бумажке "машина стоит за углом") тоесть самих данных в переменной нет, она ссылается на область памяти где хранятся сами данные.

                                                                Цитата
                                                                то как например я должен обходиться без динамических массивов?

                                                                а как вы узнаете размер вашего массива? ;) чтоб не вызвать AV
                                                                если для строк еще боле менее узнать размер (ну напр по терминирующему #0)
                                                                то как узнать размер структуры
                                                                ExpandedWrap disabled
                                                                  mass2 : array of integer;

                                                                ?
                                                                в от с
                                                                ExpandedWrap disabled
                                                                  mass2 : array of string;


                                                                вообще грабли, вот разберем этот пример

                                                                mass2 : array of string;
                                                                есть не что иное как
                                                                указатель на область памяти, где хранится
                                                                массив, произвольной длинны, указателей, которые ссылаются на
                                                                области памяти, произвольной длинны, где данные, теоритически, оканчиваются на #0

                                                                вот мы и пришли к тому что "сложные" структуры, (тоесть такие где используются переменные, с неизвестным размером") лучше сохранять в какую либо БД, а какая это БД будет вам решать, но учтите что в ней каждый раз должно сохранятся неизвестное количество полей с произвольной длинной

                                                                ЗЫ смотрите в сторону XML
                                                                Сообщение отредактировано: Virtuals -
                                                                  Цитата Virtuals @
                                                                  потому что это указатель pointer
                                                                  Потом уже догадался )
                                                                  Цитата Virtuals @
                                                                  есть не что иное как указатель на область памяти, где хранится, массив, произвольной длинны, указателей, которые ссылаются на области памяти, произвольной длинны, где данные, теоритически, оканчиваются на #0
                                                                  Ясненько! )
                                                                  Цитата Virtuals @
                                                                  вот мы и пришли к тому что "сложные" структуры, (тоесть такие где используются переменные, с неизвестным размером") лучше сохранять в какую либо БД
                                                                  Не катит, не спрашивайте почему, просто БД в этом случае мне не подходит...
                                                                  Ладно, я уже почти смирился со способом предложенным Демо. )) Всем спасибо, вопрос решен.
                                                                    R@RED

                                                                    Есть один вариант. Но насколько он сложен(или прост) не скажу, пока не попробую реализовать сам.
                                                                    Подумаю немного-)
                                                                      Буду очень рад свежей идее! =)
                                                                        Я тебе уже дал идею в #2. То, что говорит Rouse по этому поводу - фигня. Но если уж хочется подстраховаться, то можно писать файл в текстовом виде, там уж разночтений не будет.
                                                                          Пример заготовки для копирования в TStream любой структуры:
                                                                          Необходимо описание самой структуры (packed record) и строка с описанием типов полей: один символ - одно поле в структуре.
                                                                          Это лишь заготовка, необходимо тестировать в различных условиях.

                                                                          ExpandedWrap disabled
                                                                            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.


                                                                          Пример использования:

                                                                          ExpandedWrap disabled
                                                                            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;
                                                                          Сообщение отредактировано: Демо -
                                                                          0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                                                          0 пользователей:


                                                                          Рейтинг@Mail.ru
                                                                          [ Script execution time: 0,0906 ]   [ 16 queries used ]   [ Generated: 2.05.24, 06:00 GMT ]