系列130_Delphi 如何保存和加载对象 (教程)

2020-04-03







01_保存和检索对象



此示例保存类类型对象的数据。
有多种不使用数据库而存储数据的方法,但是最通用的方法是创建一个从TComponent派生的类并将其另存为已发布的属性。这使您可以处理大多数类型的数据。当与TComponentList结合使用时,它功能强大,但是在这里,它存储和检索了一组名为TData的属性的对象。
  • (1)创建一个名为TData的类的实例

  • (2)为每个属性设置一个值

  • (3)保存

  • (4)保存前读出并显示设置值

我正在按照以下过程进行测试。TData也具有类类型的属性。保存并读取时,可以看到这些属性也已保存。这意味着,当您保存一个类的对象时,还可以在其属性中保存另一类类型的对象。
可以保存的数据只是发布中定义的属性。需要存储的数据(包括类类型对象)定义为发布的属性。保存未发布的属性(在我的组件中使用)需要特殊方法。




unit Unit1; interface uses    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,    Dialogs, StdCtrls, ExtCtrls, ExtDlgs; type    TSubData = class;    TData = class(TComponent)    private     FIntVal   : Integer;     FColor   : TColor;     FFont    : TFont;     FSubData : TSubData;     procedure SetFont(const Value: TFont);     procedure SetSubData(const Value: TSubData);    protected    public     constructor Create(AOwner: TComponent);override;     destructor Destroy; override;    published     property IntVal   : Integer   read FIntVal   write FIntVal;     property Color   : TColor   read FColor    write FColor;     property Font    : TFont    read FFont     write SetFont;     property SubData : TSubData read FSubData   write SetSubData;    end;    TSubData = class(TPersistent)    private     FName : String;     FID   : Integer;    public    published     property Name : String   read FName write FName;     property ID   : Integer read FID   write FID;    end;    TForm1 = class(TForm)     Button1: TButton;     Button2: TButton;     Button3: TButton;     Memo1: TMemo;     procedure FormCreate(Sender: TObject);     procedure Button1Click(Sender: TObject);     procedure Button2Click(Sender: TObject);     procedure Button3Click(Sender: TObject);    private         FTestData : TData;     FFileName : TFileName;    public        end; var    Form1: TForm1; implementation {$R *.DFM} { TData } //-------------------------------------------------- --------------------------- //   创建TData类 //   在此处创建对象类型属性 //-------------------------------------------------- --------------------------- constructor TData.Create(AOwner: TComponent); begin    inherited Create(AOwner);    FSubData := TSubData.Create;    FFont    := TFont.Create; end; //-------------------------------------------------- --------------------------- //   销毁TData类,同时销毁创建的对象 //-------------------------------------------------- --------------------------- destructor TData.Destroy; begin    FreeAndNil(FSubData);    FreeAndNil(FFont);    inherited; end; //-------------------------------------------------- --------------------------- //   字体对象设置 //-------------------------------------------------- --------------------------- procedure TData.SetFont(const Value: TFont); begin    FFont.Assign(Value); end; //-------------------------------------------------- --------------------------- //   SubData对象设置 //-------------------------------------------------- --------------------------- procedure TData.SetSubData(const Value: TSubData); begin    FSubData.Assign(Value); end; //================================================== ========================== //   生成Form时,也会生成TData类对象TestData //   AFileName是保存文件名 //================================================== ========================== procedure TForm1.FormCreate(Sender: TObject); begin    FTestData   := TData.Create(Self);    FFileName := ExtractFilePath(Application.ExeName) + 'ATest.dat'; end; //================================================== ========================== //   设置运行检查数据 //   当然,如果这些值是固定的,则可以使用TData的构造函数进行设置。 //   (或使用构造函数执行初始设置) // //   在此代码中,它不会显示在Memo1中,因为Memo1中没有代码可显示 //================================================== ========================== procedure TForm1.Button1Click(Sender: TObject); var    LFont : TFont; begin    if Assigned(FTestData) then begin     LFont := TFont.Create;     try       LFont.Size            := 12;       LFont.Color           := clBlue;       FTestData.Font         := LFont;       FTestData.IntVal       := 2005;       FTestData.Color        := clMoneyGreen;       FTestData.SubData.Name := 'Mr.XRAY';       FTestData.SubData.ID   := 1234567890;     finally       FreeAndNil(LFont);     end;    end; end; //================================================== ========================== //   保存当前数据 //   由于它是TComponent的派生类属性,因此仅WriteComponent可以 //================================================== ========================== procedure TForm1.Button2Click(Sender: TObject); var    LFileStream : TFileStream; begin    LFileStream := TFileStream.Create(FFileName, fmCreate);    try     if Assigned(FTestData) then begin       LFileStream.WriteComponent(FTestData);     end;    finally     FreeAndNil(LFileStream);    end; end; //================================================== ========================== //   读取并显示保存的数据 //   由于它是TComponent派生类的属性,因此只有ReadComponent可以 //================================================== ========================== procedure TForm1.Button3Click(Sender: TObject); var    LFileStream : TFileStream;    LTestData   : TData; begin    Memo1.Clear;    //创建另一个名称为TData的对象以确认读取的数据    LTestData   := TData.Create(Self);    try     LFileStream := TFileStream.Create(FFileName, fmOpenRead);     try       LFileStream.ReadComponent(LTestData);     finally       LFileStream.Free;     end;     //显示读取的数据     Memo1.Lines.Add(IntToStr(LTestData.IntVal));     Memo1.Lines.Add(LTestData.SubData.Name);     Memo1.Lines.Add(IntToStr(LTestData.SubData.ID));     Memo1.Color:=LTestData.Color;     Memo1.Font.Assign(LTestData.Font);    finally     //立即丢弃,因为这是测试     FreeAndNil(LTestData);    end; end;

end.



02_使用TFileStream保存和加载组件



这是保存单个组件的示例。

这次不是保存组件的状态,而是保存组件本身。
只能创建一个具有相同名称的组件。因此,在读取之前,会将原来组件删除。

在此示例代码中,只能保存已发布的属性。发布的属性就是在对象属性器中显示的属性。


图片1:界面如下

图片2:从文件加载Panel


清单2.
使用TFileStream保存和检索组件的示例


unit Unit1; interface uses    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,    Dialogs, StdCtrls, ExtCtrls, ExtDlgs; type    TForm1 = class(TForm)     Button1: TButton;     Button2: TButton;     Panel1: TPanel;     procedure Button1Click(Sender: TObject);     procedure Button2Click(Sender: TObject);    private     { Private   }    public     { Public   }    end; var    Form1: TForm1; implementation {$R *.dfm} //================================================== ========================== //   将组件保存到文件 //================================================== ========================== procedure TForm1.Button1Click(Sender: TObject); var    LFileName   : String;    LFileStream : TFileStream; begin    LFileName   := 'AAA.dat';    LFileStream := TFileStream.Create(LFileName, fmCreate);    try     if Assigned(Panel1) then begin       LFileStream.WriteComponent(Panel1);     end;    finally     FreeAndNil(LFileStream);    end; end; //================================================== ========================== //   加载并显示已保存的组件 //================================================== ========================== procedure TForm1.Button2Click(Sender: TObject); var    LFileName   : String;    LFileStream : TFileStream;    LPanel      : TPanel; begin    //保存Panel1组件时,名字也会一起保存    //先删除,因为无法创建具有相同名称的组件    FreeAndNil(Panel1);    Update;    Sleep(1000);    LFileName   := 'AAA.dat';    LPanel   := TPanel.Create(Self);    LFileStream := TFileStream.Create(LFileName, fmOpenRead);    try     //如果不指定了parent,否则无法显示     LPanel.Parent := Self;     //读取组件     LFileStream.ReadComponent(LPanel);     Application.MessageBox(PChar(LPanel.Name), '加载成功');    finally     LFileStream.Free;    end; end; end.
阅读295