Delphi 2010:如何将整个记录保存到文件中?
我定义了一个记录,其中包含许多不同类型的字段(整数、实数、字符串……加上“数组……”的动态数组)。 我想将其作为一个整体保存到一个文件中,然后能够将其加载回我的程序中。我不想单独保存每个字段的值。 文件类型(二进制或 ascii 或...)并不重要,只要 Delphi 可以将其读回记录即可。
您有什么建议吗?
I have defined a record which has lots of fields with different types (integer, real , string, ... plus dynamic arrays in terms of "array of ...").
I want to save it as a whole to a file and then be able to load it back to my program. I don't want to go through saving each field's value individually.
The file type (binary or ascii or ...) is not important as long Delphi could read it back to a record.
Do you have any suggestions?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
只要不使用动态数组,您就可以直接将记录的内存加载到流中或从流中保存记录的内存。因此,如果您使用字符串,则需要修复它们:
您甚至可以立即加载或保存记录数组!
如果您想编写动态内容:
之后,您可以读回它:
You can load and save the memory of a record directly to and from a stream, as long as you don't use dynamic arrays. So if you use strings, you need to make them fixed:
You can even load or save an array of record at once!
In case you want to write dynamic content:
After that, you can read it back:
正如这里所承诺的那样,它是: https://github.com/KrystianBigaj/kblib
当您定义时记录为:
您可以通过以下方式将整个动态记录保存到流(作为二进制数据):
将其加载回来:
它不需要是记录,您可以对任何动态类型执行相同的操作,例如:
在Delphi 2006/2009/XE上测试。许可证:MPL 1.1/GPL 2.0/LGPL 3.0
请参阅自述文件以获取信息。
As promised here it is: https://github.com/KrystianBigaj/kblib
When you defined for example record as:
You can save whole dynamic record to stream (as binary data) by :
To load it back:
It not need to be a record, you can do same for any dynamic type like:
Tested on Delphi 2006/2009/XE. License: MPL 1.1/GPL 2.0/LGPL 3.0
See readme for information.
另一个非常适合记录的选项 (Delphi 2010+) 是使用 SuperObject 库。例如:
我还使用简单的
TArray
动态数组对此进行了简要测试,并且存储和加载数组元素没有问题。Another option which works very well for records (Delphi 2010+) is to use the SuperObject library. For example:
I also tested this briefly with a simple
TArray<Integer>
dynamic array and it did not have a problem storing and loading the array elements.另一种解决方案,从 Delphi 5 到 XE,均可用 作为开源单元。
事实上,它实现了:
序列化使用优化的二进制格式,并且能够将任何记录或动态数组保存和加载为
RawByteString
。我们在 ORM 中使用它,将动态数组属性等高级类型存储到数据库后端。迈向数据库分片架构的第一步。
Another solution, working from Delphi 5 up to XE, is available as an OpenSource unit.
In fact, it implements:
RecordEquals, RecordSave, RecordSaveLength, RecordLoad
;TDynArray
object, which is a wrapper around any dynamic array, able to expose TList-like methods around any dynamic array, even containing records, strings, or other dynamic arrays. It's able to serialize any dynamic array.Serialization uses an optimized binary format, and is able to save and load any record or dynamic array as
RawByteString
.We use this in our ORM, to store high-level types like dynamic array properties into a database back-end. First step to a DB-Sharding architecture.
除了指示您如何执行此操作的答案之外,还请注意以下内容:
您必须注意,将记录写入文件将是特定于 Delphi 版本的(通常:特定于共享共享的一系列 Delphi 版本)底层数据类型的内存布局相同)。
仅当您的记录不包含托管类型的字段时,您才能执行此操作。这意味着字段不能是以下托管类型:字符串、动态数组、变体和引用类型(例如 指针,程序类型、方法引用、接口 或 类)和文件类型,或包含这些管理类型的类型。这基本上限制于这些非托管类型:
与其将记录写入文件或从文件中写入记录,不如使用类实例并进行转换它们与 JSON 相互转换,然后写入相当于文件的 JSON 字符串并将其读回。
您可以使用此单元为您进行 JSON 转换(应与 Delphi 2010 及更高版本一起使用;肯定适用于 Delphi XE 和向上)从
此位置我希望这可以帮助您了解事物的概况。
——杰罗恩
In addition to the answers that indicate how you do this, please also be aware of these:
You must be aware that writing records out to a file will be Delphi version specific (usually: specific to a series of Delphi versions that share the same memory layout for the underlying data types).
You can only do that if your record does not contain fields of a managed type. Which means that fields cannot be of these managed types: strings, dynamic arrays, variants, and reference types (like pointers, procedural types, method references, interfaces or classes) and file types, or types that contain those manages types. Which basically limits to to these unmanaged types:
In stead of writing out records to/from a file, it might be better to go with class instances and convert them to/from JSON, and them write the JSON string equivalent to a file and read it back in.
You can use this unit to do the JSON conversion for you (should work with Delphi 2010 and up; works for sure with Delphi XE and up) from
this locationthis location.I hope this helps you getting an overview of things.
--jeroen
您还可以定义一个对象而不是记录,这样您就可以使用 RTTI 将对象保存为 XML 或其他格式。如果你有D2010或XE,你可以使用DeHL来序列化它:
Delphi 2010 DeHL 序列化 XML 和自定义属性:如何它有效吗?
但是如果你“google”你可以找到其他带有 RTTI 和序列化的库(带有 D2007 等)
You could also define an object instead of a record, so you can use RTTI to save your object to XML or whatever. If you have D2010 or XE, you can use DeHL to serialize it:
Delphi 2010 DeHL Serialization XML and custom attribute : how it work?
But if you "google" you can find other libs with RTTI and serialization (with D2007 etc)
如果您有动态字符串或数组,则无法“整体”写入记录。我不会使用旧式的最多 25 个字符的字符串,而是向记录添加方法,以便能够将其自身“流式传输”到流,或者更好地使用 TFiler 后代:
If you have dynamic strings or array you can't write the record "as a whole". Instead of using old style-25 characters max strings, I would add methods to the record to be able to "stream" itself to a stream, or better using a TFiler descendant:
来自 delphibasics 的代码:
Codes from delphibasics :
保存包含动态数组或实际字符串(或其他“托管”类型)的记录的问题是,它不是包含所有内容的大内存块,它更像是一棵树。某人或某事需要以某种方式检查所有内容并将其保存到存储中。其他语言(例如 Python)包括各种工具,可将大多数对象转换为文本(序列化)、将其保存到磁盘并重新加载(反序列化)。
即使 Delphi 不存在 Embarcadero 提供的解决方案,也可以使用 Delphi 2010 中提供的扩展 RTTI 来实现。DeHL 库中提供了现成的实现 (这是一篇关于它的博客文章) - 但我不能透露太多关于实现的信息,我从未使用过 DeHL。
另一种选择是您想要避免的:手动将记录序列化到 TStream;其实难度不可谓不大。这是我通常用来将对象读/写到文件流的代码:
The problem with saving a record containing dynamic array or real strings (or other "managed" types for that matter) is, it's not an big blob of memory containing everything, it's more like a tree. Someone or something needs to go over everything and save it to storage, somehow. Other languages (Python for example) include all sorts of facilities to transform most objects to text (serialize it), save it to disk and reload it (deserialize it).
Even though a Embarcadero-provided solution doesn't exist for Delphi, one can be implemented using the extended RTTI available in Delphi 2010. A ready-made implementation is available in the DeHL library (here's a blog post about it) - but I can't say much about the implementation, I never used DeHL.
An other option is the one you want to avoid: manually serialize the record to an TStream; It's actually not half difficult. Here's the kind of code I usually use to read/write objects to a file stream: