2

シミュレーション プログラムの場合、私は Delphi 2010 で作業しています。シミュレーションは問題ではありませんが、大量のデータ コレクションを使用する必要があるため、問題が発生します。データは Excel シートで利用できるため、Delphi でこのデータを編集する必要はありませんが、Excel シートからこのデータを収集するには約 10 分かかります。プログラムを実行するたびにデータを収集する必要がない限り、これは問題ではありません。そこで、すべてのデータを収集して可視化するプログラムを作成しましたが、ここでは問題ではなく、保存します。ただし、構造を失うことなく「Delphi形式」に保存することはできないため、数秒でロードできます。

私は Delphi の経験が豊富ではないので、長い間解決策を探しましたが、何が最善かを理解できませんでした。データを構造化する私の方法は間違っていると思いますが、シンプルでうまくいきました。ただし、データを保存するためのより良い方法がある場合は、そのように言ってください。ただし、「xml ファイル」、「ジェネリック」、または「Ttreeview」を使用するだけでなく、さらに説明が必要であることを覚えておいてください。(読みましたが、使用できませんでした)。

データは次のとおりです: 私はこの製品を作りました, 次の製品はこれです, だから私はきれいにする必要がありますか? 正しいか間違っているか。

データは、製品番号 (整数) を持つクラス (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 SaveToStream

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 の質問を参照してください- パフォーマンスが必要な場合は、Big Table ライブラリをご覧ください。

于 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 に答える