2011-03-14 71 views
0

最終,我的目標是能夠在sqlite BLOB字段中保存一組記錄數據結構,但在此期間,我試圖序列化一組記錄並將其存儲在TMemoryStream中。在情況下,它可能是相關的,我使用Tim Anderson's sqlite wrapper(Unicode)的2010年與德爾福如何將「記錄數組」保存到TMemoryStream(然後存儲在sqlite BLOB字段中)?

這是我記錄的聲明數組:

type 
    TPerson = array of packed record 
    sCountry: string[50]; 
    sFullName: string[100]; 
    sAddress: string[100]; 
    sCity: string[30]; 
    sEmployer: string[100]; 
    end; 

var 
    MyPeople  : TPerson; 

這裏是我目前使用的序列化此數組的代碼記錄到TMemoryStream。問題是,這是行不通的:在任如何一般序列記錄的陣列到內存流,或更好的方法來存儲一組記錄在一個SQLite BLOB字段

var 
    i : integer; 
    ms : TMemoryStream: 
    ms2 : TMemoryStream;  
    TestPeople : TPerson; 
    sldb    : TSQLiteDatabase; 
begin 
    ms := TMemoryStream.Create; 
    ms2 := TMemoryStream.Create; 
    sldb := TSQLiteDatabase.Create(slDBPath); //sldBPath is a global variable with path to sqlite db 
    try 
     i := Length(MyPeople); 
     ms.Write(i, 4); 
     ms.Write(pointer(MyPeople)^, i * sizeOf(MyPeople)); 
     /// 
     ms2.Read(i, 4); 
     SetLength(ms2, i); 
     ms2.Read(pointer(TestPeople)^, i * sizeOf(TestPeople)); 

     WriteLn('#############' + ms2[0].sFullName); //check if we can read data back 

     sQuery := 'UPDATE PersonDirectory SET fldPersonBlob = ? WHERE id = "' + 42 + '";'; 
     sldb.UpdateBlob(sQuery, ms); 

    finally 
     ms.Free; 
     ms2.Free; 
     sqldb.Free; 
    end; 
end; 

任何想法?

回答

2

使TPerson成爲打包記錄,並將TPerson聲明爲TPerson數組。

type 
    TPerson = packed record 
    sCountry: string[50]; 
    sFullName: string[100]; 
    sAddress: string[100]; 
    sCity: string[30]; 
    sEmployer: string[100]; 
    end; 
    TPersons = array of TPerson; 
var 
    MyPeople: TPersons; 

這可以讓你獲得中SizeOf(TPerson)來獲取記錄的大小合適,而長度(MyPeople)會給你的數組的長度。將它們相乘得到總字節大小。這應該讓你開始。

另請注意,某些讀寫操作從流的開始處開始,而其他讀取和寫入操作在當前的position處繼續。在將流的內容複製到另一個流之前,有時需要將position設置爲0。該文件將提到這一點。

+0

元素的大小仍然可以找到:'SizeOf(MyPeople [0])'。 – 2011-03-14 00:57:54

+1

是的,你說得對,但是如果你像這樣分開代碼,代碼會更加清晰。由於TPersons可以包含多個人,所以命名也更好。 :) – GolezTrol 2011-03-14 01:17:18

+1

同意,尤其是命名! – 2011-03-14 01:44:09

1

也許我錯了,但你寫在毫秒和從讀取ms2

ms2是一個內存流,但不指向ms指向的內存相同的內容。我認爲ms2將不會從讀取內容ms如果您不更改您的代碼。

如果需要放毫秒內容爲MS2,嘗試

ms2.LoadFromStream(ms); 

你開始閱讀內容之前。

當然,您需要知道單個記錄的大小來完成正確的數學計算。

+0

我認爲Mick並沒有公佈他的所有代碼,可能有代碼在'///'部分做這件事。 – 2011-03-14 01:50:30

+0

另外請注意,如果你是對的,你需要在調用'ms2.LoadFromStream'之前設置'ms.Position:= 0'。如果Mick *發佈了整個代碼(並且Sertac是錯誤的),那麼你做了一個很好的捕獲。 :) – 2011-03-14 02:00:55

1

您可以使用純字符串使用記錄數組,然後使用我們的TDynArray包裝器將它們保存到流中。

它會比短字符串使用更少的空間,因爲它只會寫入字符串使用的字符。例如,定義爲字符串[100]的sEmployer在直接存儲時總是使用101個字節。而使用我們的TDynArray,它只會使用字符數加1。

從德爾福6到XE的作品。

type 
    TPerson = packed record 
    sCountry: string; 
    sFullName: string; 
    sAddress: string; 
    sCity: string; 
    sEmployer: string; 
    end; 
    TPersons = array of TPerson; 

var 
    MyPeople: TPersons; 

(...) 
procedure SavePeopleToStream(Stream: TMemoryStream); 
begin 
    DynArray(TypeInfo(TPersons),MyPeople).SaveToStream(Stream); 
end; 

您已經在TDynArray中使用了相反的LoadFromStream方法,以及更多。 見this blog entry to get this wrapper

附加說明:這很有趣,這是相同的確切功能I'm about to add to our ORM:將動態數組內容存儲在BLOB字段中,編碼爲二進制。但在我們的例子中,所有的都將自動得益於Delphi RTTI。另外還有一個使用JSON傳輸的客戶端/服務器層,使其更符合n層標準。

+1

就是這樣:我在我們的框架中添加了動態數組作爲有效的已發佈屬性。還有'TPersistent,TStrings'和'TCollection'。動態數組存儲在BLOB中,其中'TPersistent,TStrings'和'TCollection'存儲在TEXT字段中,JSON編碼(如JSON數組和/或對象)。 – 2011-04-27 05:50:45

相關問題