Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2014.06.22;
Скачать: CL | DM;

Вниз

Запись класса в TStream   Найти похожие ветки 

 
solomon ©   (2012-01-09 17:38) [0]

Есть класс

type
 TPostingClass = class
 private
 protected
 public
   ProjectName: string[255];
   ProjectMode:
   AccountsName: tstringlist;

   constructor Create;
 end;

constructor TPostingClass.Create;
begin
AccountsName:=tstringlist.Create;
end;

Создаем несколько экземпляров класса, заполняем их данными и записываем в поток TasksStream: TMemoryStream являющийся глобальной переменной:

var
p:TPostingClass;
begin
p:=TPostingClass.Create;
p.ProjectName:="первый аккаунт";
p.SourceType:=1;
p.AccountsName.Add("1 акк");
TasksStream.WriteBuffer(P, SizeOf(TPostingClass));
p.Free;

p:=TPostingClass.Create;
p.ProjectName:="второй аккаунт";
p.SourceType:=1;
p.AccountsName.Add("1 акк");
p.AccountsName.Add("2 акк");
TasksStream.WriteBuffer(P, SizeOf(TPostingClass));
p.Free;

p:=TPostingClass.Create;
p.ProjectName:="третий аккаунт";
p.SourceType:=1;
p.AccountsName.Add("1 акк");
p.AccountsName.Add("2 акк");
p.AccountsName.Add("3 акк");
TasksStream.WriteBuffer(P, SizeOf(TPostingClass));
p.Free;

Читаем данные из стрима:
Memo1.Clear;
TasksStream.Position:=0;

for k:=1 to 3 do
begin
   p:=TPostingClass.Create;
   TasksStream.ReadBuffer(P, SizeOf(TPostingClass));
   memo1.Lines.Add("ProjectName= "+p.ProjectName);
   memo1.Lines.Add("ProjectMode= "+inttostr(p.ProjectMode));

   for i:=0 to p.AccountsName.Count-1 do
    memo1.Lines.Add("AccountsName="+p.AccountsName.strings[i]);

   p.Free;
                                     
 memo1.Lines.Add("---");
end;

В итоге в Memo1 получаю

ProjectName=
ProjectMode= 0
---
ProjectName=
ProjectMode= 0
---
ProjectName=
ProjectMode= 0
---

не пойму в чем дело?


 
solomon ©   (2012-01-09 17:41) [1]

Прикол в том, что если при чтении данных из стрима строчки
p:=TPostingClass.Create;
и
p.free

убрать, то получаем в Memo1:

ProjectName= 
ProjectMode= 0
AccountsName= 1 акк
AccountsName= 2 акк
AccountsName= 3 акк
---
ProjectName= 
ProjectMode= 0
AccountsName= 1 акк
AccountsName= 2 акк
AccountsName= 3 акк
---
ProjectName= 
ProjectMode= 0
AccountsName= 1 акк
AccountsName= 2 акк
AccountsName= 3 акк
---

вообще не ясно почему в данном случае не вылезло AV на строке TasksStream.ReadBuffer(P, SizeOf(TPostingClass)); ведь объект P то не создан


 
DVM ©   (2012-01-09 18:57) [2]


> вообще не ясно почему в данном случае не вылезло AV на строке
> TasksStream.ReadBuffer(P, SizeOf(TPostingClass)); ведь объект
> P то не создан

потому и вылезло, что не создан, что же еще ждать при обращении по левому указателю.


 
solomon ©   (2012-01-09 19:28) [3]

DVM вы не внимательно читали, я написал что AV НЕ вылезло, меня это и удивило.

Но вопрос в другом, почему класс не сохраняется в стрим, ну или если сохраняется то не читается из него корректно?


 
~AQUARIUS~   (2012-01-09 19:36) [4]

Сделайте ShowMessage(IntToStr(SizeOf(TPostingClass))) и вы удивитесь еще больше.
А вообще, ничего странного в вашем случае нет. Потому что переменная p - это не обьект класса TPostingClass, а указатель на такой обьект. Т.е. вы в стрим записываете не поля, а указатели, которые после чтения в общем случае не имеют смысла


 
solomon ©   (2012-01-09 19:44) [5]

Ничего не понимаю, почему же P это не объект класса TPostingClass, я ведь его  не описывал как указатель то ?

Ладно пусть будет даже указателем, но как мне решить проблему, как записать и считать класс из стрима?


 
~AQUARIUS~   (2012-01-09 19:58) [6]

А и не надо описывать. Дельфи - не С++, там все такие переменные - указатели.
Если по-правильному, ваш класс должен иметь методы для сохранения и записи - типа LoadFromStream, SaveToStream, как большинство обьектов VCL/RTL. Эти методы и должны выполнять всю работу. Можно сделать их виртуальными и перекрывать в наследниках. Записывать обьект в бинарном виде (разименовав р) тоже нельзя - там есть еще служебные поля - указатель на метакласс и в новых версиях - указатель на монитор. После чтения эти указатели тоже будут невалидными


 
DVM ©   (2012-01-09 19:59) [7]


>  но как мне решить проблему, как записать и считать класс
> из стрима?
>
>

TWriter + TReader


 
~AQUARIUS~   (2012-01-09 20:02) [8]

DVM

А они разве запишут не-published поля?


 
DVM ©   (2012-01-09 20:04) [9]


> ~AQUARIUS~   (09.01.12 20:02) [8]


> А они разве запишут не-published поля?

Сами по себе они вообще ничего не запишут, сами пишем нужные поля в нужном порядке, сами и считываем в нужном порядке. Сами и префикс класса назначаем.


 
DVM ©   (2012-01-09 20:07) [10]

У меня большинство классов вот от такого унаследованы, в потомках надо определить ReadData и WriteData:


 TBaseStreamedObject = class(TPersistent)
 strict protected
   procedure ReadData(Reader : TReader); virtual; abstract;
   procedure WriteData(Writer : TWriter); virtual; abstract;
   procedure SaveToStream(Stream : TStream); virtual; abstract;
   procedure LoadFromStream(Stream : TStream); virtual; abstract;
   procedure SaveToFile(FileName : string); virtual; abstract;
   procedure LoadFromFile(FileName : string); virtual; abstract;
 end;

 TStreamedObject = class(TBaseStreamedObject)
 public
   procedure SaveToStream(Stream : TStream); override;
   procedure LoadFromStream(Stream : TStream); override;
   procedure SaveToFile(FileName : string); override;
   procedure LoadFromFile(FileName : string); override;
 end;

....

procedure TStreamedObject.LoadFromStream(Stream: TStream);
var
 Reader: TReader;
begin
 Reader := TReader.Create(Stream, $FF);
 try
   ReadData(Reader);
 finally
   FreeAndNil(Reader);
 end;
end;

//------------------------------------------------------------------------------

procedure TStreamedObject.SaveToStream(Stream: TStream);
var
 Writer: TWriter;
begin
 Writer := TWriter.Create(Stream, $FF);
 try
   WriteData(Writer);
 finally
   FreeAndNil(Writer);
 end;
end;

//------------------------------------------------------------------------------

procedure TStreamedObject.SaveToFile(FileName : string);
var
 Stream: TFileStream;
begin
 Stream := TFileStream.Create(FileName, fmCreate);
 try
   SaveToStream(Stream);
 finally
   Stream.Free;
 end;
end;

//------------------------------------------------------------------------------

procedure TStreamedObject.LoadFromFile(FileName : string);
var
 Stream: TFileStream;
begin
 Stream := TFileStream.Create(FileName, fmOpenRead);
 try
   LoadFromStream(Stream);
 finally
   Stream.Free;
 end;
end;


 
DVM ©   (2012-01-09 20:09) [11]

например:


procedure TSCMBaseAgentInfo.ReadData(Reader : TReader);
begin
 inherited;
 with Reader do
   begin
     FAgentUniqueID := ReadInteger;
     FAgentName := ReadString;
     Read(FAgentType, SizeOf(TSCMAgentType));
     FAgentVersion := ReadString;
   end;
end;

//------------------------------------------------------------------------------

procedure TSCMBaseAgentInfo.WriteData(Writer : TWriter);
begin
 inherited;
 with Writer do
 begin
   WriteInteger(FAgentUniqueID);
   WriteString(FAgentName);
   Write(FAgentType, SizeOf(TSCMAgentType));
   WriteString(FAgentVersion);
 end;
end;



Страницы: 1 вся ветка

Текущий архив: 2014.06.22;
Скачать: CL | DM;

Наверх




Память: 0.5 MB
Время: 0.005 c
15-1385843401
Юрий
2013-12-01 00:30
2014.06.22
С днем рождения ! 1 декабря 2013 воскресенье


1-1326116288
solomon
2012-01-09 17:38
2014.06.22
Запись класса в TStream


2-1377270653
Zheksonz
2013-08-23 19:10
2014.06.22
Sender


15-1386058324
LDV
2013-12-03 12:12
2014.06.22
html-редактор


2-1377531220
dis12345
2013-08-26 19:33
2014.06.22
Установить курсор в вид по умолчанию