官方QQ:  16643506

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







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. 
联系电话:
020-00000000
联系电话:
020-00000000
联系电话:
020-12345678