如何将“记录数组”保存到TMemoryStream(然后存储在sqlite BLOB字段中)?

时间:2011-03-14 00:32:31

标签: delphi sqlite delphi-2010

最终我的目标是能够在sqlite BLOB字段中保存一组记录数据结构,但在此期间,我正在尝试序列化一组记录并将其存储在TMemoryStream中。如果它可能是相关的,我使用Tim Anderson's sqlite wrapper(unicode)与Delphi 2010。

这是我的记录声明数组:

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的代码。问题是它不起作用:

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;

关于如何将记录数组序列化到TMemoryStream的任何想法,或者在sqlite BLOB字段中存储记录数组的更好方法?

3 个答案:

答案 0 :(得分:2)

将TPerson设为打包记录,并将TPersons声明为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)以获得正确的记录大小,而Length(MyPeople)将为您提供数组的长度。将它们相乘以获得总字节大小。这应该让你开始。

另请注意,某些读取和写入操作从流的开头开始,而其他操作则从当前position继续。有时需要在将流的内容复制到另一个之前将position设置为0。文档将提到这一点。

答案 1 :(得分:1)

也许我错了,但你正在写 ms 并从 ms2 阅读。

ms2 是内存流,但不指向 ms 指向的相同内存内容。我认为如果您不更改代码, ms2 将无法读取 ms 中的内容。

如果您需要将 ms 的内容添加到 ms2 ,请尝试

ms2.LoadFromStream(ms);

开始阅读内容之前。

当然,你需要知道单个记录的大小才能做正确的数学运算。

答案 2 :(得分:1)

您可以使用带有纯字符串的记录数组,然后使用我们的TDynArray包装器将它们保存到流中。

它将比shorttrings使用更少的空间,因为它只会写入字符串使用的字符。例如,定义为字符串[100]的sEmployer在直接存储时将始终使用101个字节。而使用我们的TDynArray,它只会使用字符数加一。

从Delphi 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-Tier。