最终我的目标是能够在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字段中存储记录数组的更好方法?
答案 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。