2011-08-18 57 views
2

對於我在德爾福2010工作的模擬程序。模擬不是問題,但我需要使用大量的數據集合來提供問題。數據可以在excel表格中找到,所以不需要在Delphi中編輯這些數據,但是從excel表格中收集這些數據大約需要10分鐘。只要您不需要在每次運行程序時收集數據,這都不是問題。所以我製作了一個收集所有數據的程序,使其可見,而不是問題在這裏,然後存儲它。但是我不能將它存儲爲「Delphi格式」,而不會丟失結構,因此可以在幾秒鐘內加載。德爾福:將數據存儲在某種結構中

我不是那種在德爾福的經驗,我搜索了很長時間的解決方案,但不明白什麼是最好的。我認爲我構建數據的方法是錯誤的,但它很簡單,很有效。但是,如果有更好的數據存儲方式,請說出來,但請記住,我需要更多的解釋,而不僅僅是使用'xml文件','generict或'Ttreeview'。 (已閱讀但無法使用它)。

數據適用於:我做了這個產品,我做的下一個產品是這個,所以我需要清潔?對或錯。

的數據存儲與Productnumber(整數)類(TObject的),並且包含了可以作出next.This列表包含其他類(TObject中)與Productnumber(整數)的所有產品和我一個名單需要清理(布爾)。我想將此結構保存在一個文件中,而不會丟失數據並將其讀回到相同的結構中。

我希望有人能幫忙。先謝謝你。

更新:該代碼提供一點的更多信息(修改爲英文)

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; 

現在我要保存所有內容的全局列表,所以我可以用相同的結構加載它。

+0

猜測你的數據結構是什麼有點困難...你是什麼意思的「乾淨(布爾)」:一個布爾屬性? –

+0

@Arnand:據我所知,它是一個含義爲「我需要清理(上)」的布爾值。 –

+1

「我認爲我構建數據的方法是錯誤的,但它很簡單並且很有效」 - 如果數據結構很簡單並且可行,那怎麼會出錯? –

回答

19

你需要的是所謂的「序列化」機制。

1.標準方式

1.1 SaveToStream

在Delphi,我們通常實現一個SaveToStream方法,這將節省每個對象的內容中的目的地TStream(一個或TFileStream一個TMemoryStream)。

你必須手工編寫序列化。

1.2 DFM狀流

TWriter參見/ TReader類。

如果您在發佈的屬性中定義數據,則可以使用這些標準的Delphi類對它們進行序列化。

對於某些能夠序列化任何TCollection往返JSON內容的方法,請參見this blog article

2. RTTI

例如見this SO question

特別是,新的增強RTTI(自Delphi 2010開始提供)爲序列化開闢了新的機會。

3.使用記錄,而不是類

如果每個項目不存儲大量的內容(一些整數/布爾),它可能是有意義的使用記錄,而不是對象。對於速度和內存消耗/碎片,這可能是值得的。

這裏是some wrapper able to serialize any dynamic array,甚至包含嵌套的記錄或動態數組。

4.使用一個數據庫引擎

也許更好的做法是不是已經陷入了一種非發展的二進制形式的數據,專有的應用程序。如果你想添加一個屬性,你必須手工管理它。或者,如果您想從其他應用程序訪問您的數據,可能會很困難。

有很多數據庫解決方案 - 而不是使用外部數據庫(如MS SQL,FireBird或Oracle),將數據庫嵌入到應用程序中可能是一個好主意(安裝起來更容易)。值得一提的是SQLite其中有a lot of wrappers,其中包括our version(如果您想使用MS SQL或Oracle,則可以更改爲任何其他數據庫)。

您還有其他解決方案 - 請參閱this SO question - 如果您需要性能,請查看我們的Big Table library

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; 

這是一般的想法.. 。如何加載數據回來也應該清楚。文件版本的東西在那裏,所以當數據對象發生變化時(即添加一些屬性),可以增加版本號,這樣在加載代碼中就可以將數據加載到正確版本的數據對象中。

+0

仍然缺少一個Create構造函數來初始化內部FChildProducts實例...以及一個析構函數來釋放它... –

+0

@Arnaud是的,代碼只能表示想法,而不是完美的即用型lib。只需要花費太多精力就可以編寫所有的代碼......但它應該讓OP開始。 – ain

+0

OP對於閱讀所有代碼已經非常好。直接在SO中編寫代碼始終是一種努力。 –

0

我會去Arnoud的選項#4,但使用ClientDataSet嵌套ClientDataSets。這將允許您將數據加載並保存在可彎曲的結構中,並快速顯示。查詢this pagehere查看一些嵌套的數據集信息和示例。