将 TObject 保存到文件

发布于 2024-07-15 11:18:24 字数 45 浏览 4 评论 0原文

如何将当前状态的对象保存到文件中? 这样就可以立即读取并恢复它的所有变量。

How can one save an Object, in its current state, to a file? So that it can immediately be read and restored with all its variables.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

冷默言语 2024-07-22 11:18:24

您正在寻找的称为对象持久性。 这篇文章可能会有所帮助,如果您用谷歌搜索,还有很多其他文章“德尔福持久对象”。

What you are looking for is called object persistance. This article might help, and there are many others if you google for "delphi persisting objects".

っ左 2024-07-22 11:18:24

如果您从 TComponent 继承对象,则可以使用一些内置功能将对象流式传输到文件。 我认为这只适用于简单的对象。

一些帮助您入门的示例代码:

unit Unit1;

interface

uses
  Classes;

type
  TMyClass = class(TComponent)
  private
    FMyInteger: integer;
    FMyBool: boolean;
    FMyString: string;
  public
    procedure ToFile(AFileName: string);
  published
    property MyInteger: integer read FMyInteger write FMyInteger;
    property MyString: string read FMyString write FMyString;
    property MyBool: boolean read FMyBool write FMyBool;
  end;

implementation

{ TMyClass }

procedure TMyClass.ToFile(AFileName: string);
var
  MyStream: TFileStream;
begin
  MyStream := TFileStream.Create(AFileName);
  try
    Mystream.WriteComponent(Self);
  finally
    MyStream.Free;
  end;
end;

end.

If you descend your object from TComponent, you can use some built-in functionality to stream the object to a file. I think this only works well for simple objects.

Some sample code to get you started:

unit Unit1;

interface

uses
  Classes;

type
  TMyClass = class(TComponent)
  private
    FMyInteger: integer;
    FMyBool: boolean;
    FMyString: string;
  public
    procedure ToFile(AFileName: string);
  published
    property MyInteger: integer read FMyInteger write FMyInteger;
    property MyString: string read FMyString write FMyString;
    property MyBool: boolean read FMyBool write FMyBool;
  end;

implementation

{ TMyClass }

procedure TMyClass.ToFile(AFileName: string);
var
  MyStream: TFileStream;
begin
  MyStream := TFileStream.Create(AFileName);
  try
    Mystream.WriteComponent(Self);
  finally
    MyStream.Free;
  end;
end;

end.
浅唱々樱花落 2024-07-22 11:18:24

如前所述,最简单的方法是使用 Stream 及其 WriteComponentReadComponent 方法。
请注意
- 它适用于 TComponent 的后代,而不是普通的 TObject;
- 仅针对已发布的属性(保存在 dfm 中的属性),而不是公共属性,也不是(更不用说)私有属性;
- 恢复组件时必须特别注意Name属性

您可能会在这些答案中找到一些可以使用的代码: 在Delphi中在运行时替换可视组件在运行时复制组件-时间

As already stated, the easiest way is to use a Stream and its WriteComponent and ReadComponent methods.
But be aware that :
- it works for descendants of TComponent, not plain TObject;
- only for the published properties (those saved in a dfm), not the public ones nor (a fortiori) the privwte ones;
- you have to pay a special attention for the Name property when restoring the component.

You may find some code you could use in these SO answers: Replace visual component at runtime in Delphi, Duplicating components at Run-Time

旧故 2024-07-22 11:18:24

这里还有一个您自己的 XML 方法所以

There's also a roll-your-own XML method here on S.O.

予囚 2024-07-22 11:18:24

解决方案 1. 您可以使用 JVCL TJvAppXMLFileStorage(请参见下面的代码)。 但是JVCL很大!! 你必须三思而后行,是否愿意,把如此巨大的依赖拖在你的身后,你的一生。

解决方案 2. 将对象保存到二进制文件(我的首选解决方案)。 相信我,这并不难。
使用 ccStreamMem.pas,或者更好的是我的 LightSaber 核心库.
Delphi 的所有荣耀 书。
PS:LightSaber 是 JVCL 的轻量级替代品。

以下是如何将记录保存到二进制文件的示例。 TObject 的操作是相同的!

// Supposing you have a record (could be also an object) called RAnimationParams that you want to save to disk:

INTERFACE

USES
  System.SysUtils, Vcl.Graphics, ccStreamBuff;

TYPE
  TFrameDelayType = (fdAuto, fdUser);

  RAnimationParams = record
    Color         : TColor;          
    DelayType     : TFrameDelayType;
    procedure WriteToStream (IOStream: TCubicBuffStream);
    procedure ReadFromStream(IOStream: TCubicBuffStream);
  end;

IMPLEMENTATION

procedure RAnimationParams.WriteToStream(IOStream: TCubicBuffStream);
begin
 IOStream.WriteByte    (Ord(DelayType));
 IOStream.WriteInteger (Color);
 IOStream.WritePadding (32);
end;

procedure RAnimationParams.ReadFromStream(IOStream: TCubicBuffStream);
begin
 DelayType    := TFrameDelayType(IOStream.ReadByte);
 Color        := IOStream.ReadInteger;
 IOStream.ReadPadding (32);
end;

末尾的填充允许您稍后更改记录/对象结构,而无需更改二进制文件的格式。

要实际将 RAnimationParams 保存到磁盘,您只需执行以下操作:

MyBinFile:= TCubicBuffStream.CreateRead('C:\Test.bin');
AnimationParams.WriteToStream(MyBinFile);
MyBinFile.Free;

当您想要从 Test.bin 加载 RAnimationParams 时使用相同的代码,但您使用 CreateWrite 而不是 CreateRead。

TCubicBuffStream 类甚至具有 ReadHeader/CreateWrite 等专用函数,可让您轻松添加“文件幻数”和“文件版本号”到您的二进制文件。

看? 没那么难。 它适用于任何对象,而不仅仅是 TComponent。


JVCL 的示例,但它不适用于 TObject,而仅适用于持久派生:

 uses
      JvAppXMLStorage;
    
    var
      Storage: TJvAppXMLFileStorage;
    begin
      Storage := TJvAppXMLFileStorage.Create(nil);
      try
        Storage.WritePersistent('', MyObject);
        Storage.Xml.SaveToFile('S:\TestFiles\Test.xml');
        Storage.Xml.LoadFromFile('S:\TestFiles\Test.xml');
        Storage.ReadPersistent('', MyObject);
      finally
        Storage.Free;
      end;
    end;

Solution 1. You can use JVCL TJvAppXMLFileStorage (see code below). But JVCL is huge!! You have to consider twice if you want or not, to drag such a huge dependency after you, your whole life.

Solution 2. Save your object to a binary file (my preferred solution). Believe me, it is not that hard.
Use the ccStreamMem.pas, or even better the ccStreamBuff.pas (buffered writing) in my LightSaber Core library.
You have some code examples on how to do it, in Delphi in all its glory book.
PS: LightSaber is a lightweight alternative to JVCL.

Here is an example of how to save a record to a binary file. The operation is identical for TObject!

// Supposing you have a record (could be also an object) called RAnimationParams that you want to save to disk:

INTERFACE

USES
  System.SysUtils, Vcl.Graphics, ccStreamBuff;

TYPE
  TFrameDelayType = (fdAuto, fdUser);

  RAnimationParams = record
    Color         : TColor;          
    DelayType     : TFrameDelayType;
    procedure WriteToStream (IOStream: TCubicBuffStream);
    procedure ReadFromStream(IOStream: TCubicBuffStream);
  end;

IMPLEMENTATION

procedure RAnimationParams.WriteToStream(IOStream: TCubicBuffStream);
begin
 IOStream.WriteByte    (Ord(DelayType));
 IOStream.WriteInteger (Color);
 IOStream.WritePadding (32);
end;

procedure RAnimationParams.ReadFromStream(IOStream: TCubicBuffStream);
begin
 DelayType    := TFrameDelayType(IOStream.ReadByte);
 Color        := IOStream.ReadInteger;
 IOStream.ReadPadding (32);
end;

The padding at the end allows you to change your record/object structure later, without changing the format of your binary file.

To actually save the RAnimationParams to disk you just do:

MyBinFile:= TCubicBuffStream.CreateRead('C:\Test.bin');
AnimationParams.WriteToStream(MyBinFile);
MyBinFile.Free;

Same code when you want to load the RAnimationParams back from Test.bin, but you use CreateWrite instead of CreateRead.

The TCubicBuffStream class has even dedicated functions such as ReadHeader/CreateWrite that allow you to easily add "file magic numbers" and "file version numbers" to your binary files.

See? Not so difficult. And it will work for any object, not only for TComponent.


Example for JVCL, but it won't work for TObject but only for persistent derivates:

 uses
      JvAppXMLStorage;
    
    var
      Storage: TJvAppXMLFileStorage;
    begin
      Storage := TJvAppXMLFileStorage.Create(nil);
      try
        Storage.WritePersistent('', MyObject);
        Storage.Xml.SaveToFile('S:\TestFiles\Test.xml');
        Storage.Xml.LoadFromFile('S:\TestFiles\Test.xml');
        Storage.ReadPersistent('', MyObject);
      finally
        Storage.Free;
      end;
    end;
冷默言语 2024-07-22 11:18:24

这里有一个很好的教程。 请记住,您必须具有 RTTI(运行时类型信息)才能使用此方法在运行时保存对象,因此它只会捕获类的已发布属性。

There is a good tutorial here. Keep in mind that you have to have RTTI (run time type information) to save an object at run-time using this approach, so it will only capture published properties of a class.

伴我心暖 2024-07-22 11:18:24

您的问题已经得到了一些很好的答案。 根据您实际执行的操作,可能需要使用预构建的库或组件来保存对象。 这是一个廉价且漂亮的库/组件集,使得持久化和恢复对象变得微不足道,并且非常容易(即,用一点代码)容纳对象的未发布成员的持久化:
http://www.deepsoftware.ru/rsllib/index.html 不是这样的火箭科学,但如果您正在做很多此类事情,那么该组件为其提供了一个很好的框架。

Developer Express 还包括一个通用 cxPropertiesStore 组件,作为 ExpressEditors 库的一部分,该库随其某些组件一起提供。

You've already gotten some good answers to your question. Depending on what you're actually doing, it might be desirable to use a pre-built library or component to save objects. This is an inexpensive and nifty library/component set that makes it trivial to persist and restore objects, and pretty easily (i.e., with a little bit of code) accommodates persisting even unpublished members of an object:
http://www.deepsoftware.ru/rsllib/index.html Not something that's rocket science, but if you're doing a lot of this sort of thing this component provides a nice framework for it.

Developer Express also includes a general purpose cxPropertiesStore component as part of the ExpressEditors library that comes with some of their components.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文