2

对于我在 Delphi 2010 中工作的模拟程序。模拟不是问题,但我需要使用大量数据,这会产生问题。数据在 Excel 表中可用,因此无需在 Delphi 中编辑此数据,但从 excel 表中收集此数据大约需要 10 分钟。只要您不需要在每次程序运行时都收集数据,这不是问题。所以我做了一个程序,它收集所有的数据使它可见,这里没有问题,然后存储它。但是我不能将它存储为“Delphi 格式”,而不会丢失结构,因此它可以在几秒钟内加载。

我在 Delphi 中没有那么有经验,我搜索了很长时间的解决方案,但不明白什么是最好的。我认为我构建数据的方式是错误的,但它既简单又有效。但是,如果有更好的存储数据的方法,请说出来,但请记住,我需要更多的解释,而不仅仅是使用“xml 文件”、“generict”或“Ttreeview”。(已阅读但无法使用)。

数据是:我做了这个产品,我做的下一个产品是这个,所以我需要清洗吗?对或错。

数据存储为具有 Productnumber (整数)的类(TObject)和一个包含接下来可以制作的所有产品的列表。此列表包含另一个具有 Productnumber(整数)的类(TObject)和我需要清理(布尔值)。我想将此结构保存在文件中,而不会丢失数据并将其读回相同的结构。

我希望有人能帮忙。先感谢您。

更新:提供更多信息的代码(修改为英文)

Clean_from = class(TObject)
public
  myfromNumber      : Integer;
  mylist            : TList;
published
  constructor Create;
End

Clean_To = class(TObject)
public
  myToNumber        : Integer;
  Clean             : Boolean;
End;

constructor Clean_from.Create;
begin
  inherited Create;
  myList := Tlist.Create;
end;

For i = 0 to 100 do
begin
  From:= Clean_from.create;
  for j := 0 to 10 do 
  begin 
    To := Clean_To.create;
    To.clean := true or false;
    From.myList.add(To);
  end;
  GlobalList.add(from);
end;

现在我想保存包含所有内容的全局列表,以便我可以使用相同的结构加载它。

4

2 回答 2

19

你需要的是所谓的“序列化”机制。

1.标准方式

1.1 保存到流

在 Delphi 中,我们通常实现一个SaveToStream方法,它将每个对象的内容保存在一个目标TStream(aTFileStream或 a TMemoryStream)中。

您必须手动编写序列化。

1.2 类 DFM 流

TWriter/TReader类。

如果你在发布的属性中定义你的数据,你可以使用那些标准的 Delphi 类来序列化它们。

有关能够序列化任何 JSON 内容的方法TCollection参阅此博客文章

2.RTTI

参见例如这个 SO question

特别是,新的增强型 RTTI(自 Delphi 2010 起可用)为序列化开辟了新的机会。

3. 使用记录而不是类

如果每个项目不存储大量内容(一些整数/布尔值),则使用记录而不是对象可能是有意义的。对于速度和内存消耗/碎片,这可能是值得的。

这是一些能够序列化任何动态数组的包装器,甚至包含嵌套记录或动态数组。

4.使用数据库引擎

也许更好的方法是不要让你的数据停留在一个非进化的二进制形式中,这是你的应用程序专有的。如果要添加属性,则必须手动管理它。或者,如果您想从其他应用程序访问您的数据,这可能会很困难。

周围有很多数据库解决方案——与其使用外部数据库(如 MS SQL、FireBird 或 Oracle),不如将数据库嵌入到您的应用程序中(更容易安装)。值得一提的是SQLite,它有很多包装器,包括我们的版本(如果你想使用 MS SQL 或 Oracle,它允许你更改为任何其他数据库)。

您还有其他解决方案 - 请参阅这个 SO question - 如果您需要性能,请查看我们的Big Table library

于 2011-08-18T12:01:28.407 回答
2

向您的数据对象添加SaveToStream()LoadFromStream()方法,这些方法可以将数据保存到流中并从流中加载数据。

type
  TMyData = class(TObject)
  private
    FChildProducts: TList;
    FProductnumber : integer;
    FClean: boolean;
  public
    procedure LoadFromStream(const aStream: TStream);
    procedure SaveToStream(const aStream: TStream);
  published
    property Productnumber: Integer read FProductnumber write FProductnumber;
    property Clean: Boolean reas FClean write FClean;
  end;

procedure TMyData.LoadFromStream(const aStream: TStream);
var x, cnt: Integer;
    cD: TMyData;
begin
  aStream.Read(FProductnumber, SizeOf(FProductnumber));
  aStream.Read(FClean, SizeOf(FClean));
  // read number of child products
  aStream.Read(cnt, SizeOf(cnt));
  // load child objects
  for x := 1 to cnt do begin
     cD := TMyData.create;
     cD.LoadFromStream(aStream);
     FChildProducts.Add(cD);
  end; 
end;

procedure TMyData.SaveToStream(const aStream: TStream);
var x: Integer;
begin
  aStream.Write(FProductnumber, SizeOf(FProductnumber));
  aStream.Write(FClean, SizeOf(FClean));
  // save number of child products
  x := FChildProducts.Count;
  aStream.Write(x, SizeOf(x));
  // save child objects
  for x := 0 to FChildProducts.Count - 1 do
     (FChildProducts[x] as TMyData).SaveToStream(aStream);
end;

我假设您有一些“根对象”列表,因此您可以创建一个函数或方法将它们保存/加载到/从流中,即

function SaveDataList(const List: TList;const aFileName: string);
var x: Integer;
    FS: TFileStream;
begin
  FS := TFileStream.Create(aFileName, ...);
  try
     // save file version
     x := 1;
     FS.Write(x, SizeOf(x));
     // save number of products
     x := List.Count;
     FS.Write(x, SizeOf(x));
     // save objects
     for x := 0 to List.Count - 1 do
       (List[x] as TMyData).SaveToStream(FS);
  finally
     FS.Free;
  end;
end;

这是一般的想法......如何加载数据也应该很清楚。文件版本的东西在那里,因此当数据对象更改时(即添加一些属性),您可以增加版本号,以便在加载代码中您可以将数据加载到数据对象的正确版本中。

于 2011-08-18T11:56:21.090 回答