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

发布于 2024-10-21 11:32:00 字数 1475 浏览 2 评论 0原文

最终我的目标是能够将记录数组数据结构保存在 sqlite BLOB 字段中,但在此期间我尝试序列化记录数组并将其存储在 TMemoryStream 中。如果可能相关,我正在使用 Tim Anderson 的 sqlite 包装器(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 字段中存储记录数组的更好方法,有什么想法吗?

Ultimately my goal is to be able to save an array of records data structure in a sqlite BLOB field, but in the interim I am trying to serialize an array of records and store it in a TMemoryStream. In case it may be relevant, I am using Tim Anderson's sqlite wrapper (unicode) with Delphi 2010.

This is my array of record declaration:

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;

And here is the code I am currently using to serialize this array of record to a TMemoryStream. The problem is that it doesn't work:

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;

Any ideas on either how to generally serialize an array of record to a TMemoryStream, or a better way to store an array of records in a sqlite BLOB field?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

つ低調成傷 2024-10-28 11:32:00

使 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 设置为 0。文档中会提到这一点。

Make TPerson the packed record, and declare TPersons as array of 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;

This allows you to get SizeOf(TPerson) to get the right size of the record, while Length(MyPeople) will give you the length of the array. Multiply them to get the total byte size. That should get you started.

Also note that some read and write action start from the beginning of the stream, while others continue at the current position. Setting position to 0 before copying the contents of a stream to another is sometimes needed. The documentation will mention this.

拥抱没勇气 2024-10-28 11:32:00

也许我错了,但你是用 ms 编写并从 ms2 读取的。

ms2 是一个内存流,但不要指向 ms 所指向的相同内存内容。我认为如果您不更改代码,ms2 将不会读取 ms 的内容。

如果您需要将ms的内容放入ms2中,

ms2.LoadFromStream(ms);

请在开始阅读内容之前尝试一下。

当然,您需要知道单个记录的大小才能进行正确的计算。

Maybe I wrong, but you are writing in ms and reading from ms2.

ms2 is a memory stream, but don't point to same memory content that ms is pointing. I think that ms2 will not read content from ms if you don't change your code.

If you need to put the content of ms into ms2, try

ms2.LoadFromStream(ms);

before you start to reading content.

Of course, you need to know the size of a individual record to do the right math.

⊕婉儿 2024-10-28 11:32:00

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

它将比短字符串使用更少的空间,因为它只会写入字符串使用的字符。例如,定义为 string[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 方法以及更多功能。
请参阅此博客获取此包装器的条目

附加说明:很有趣,这是同一个功能我要添加我们的 ORM:将动态数组内容存储在 BLOB 字段中,编码为二进制。但在我们的例子中,由于 Delphi RTTI,一切都将实现自动化。还有一个客户端/服务器层,使用 JSON 进行传输,使其更加符合 n-Tier 标准。

You can use an array of records with plain string, then save them into a stream with our TDynArray wrapper.

It will use less space than shortstrings, because it will write only the characters used by the string. For instance, sEmployer defined as string[100] will always use 101 bytes when stored directly. Whereas with our TDynArray, it will only use the number of chars plus one.

Works from Delphi 6 up to 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;

You've got the reverse LoadFromStream method available, and much more, in TDynArray.
See this blog entry to get this wrapper.

Additional note: It's funny, this is the same exact feature I'm about to add to our ORM: store dynamic array content in a BLOB field, encoded as binary. But in our case, all will be automated thanks to the Delphi RTTI. And there is also a Client/Server layer, using JSON for transmission, to make this more n-Tier compliant.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文