如何在Nim中编写/读取二进制数据(以类型为单位)?

huangapple go评论60阅读模式
英文:

How to write/read binary data (in type) in Nim?

问题

假设我有这个数据类型

```Nim

type
  TODO* = tuple
    atTime: float
    item: string

type
  TestData* = tuple
    timeAdded: float
    who: string
    todo: seq[TODO]
    isDone: bool


var data: TestData
# 设置并向data中添加内容的代码

因此,由于seq的存在,长度会有所变化。是否有一种直接的方法来保存/加载这些数据?
像这样的方式:
writeFile("testdata.dat", data) 然后稍后使用readFile("testdata.dat", data)?
我只发现了writeFile中的string和openArray。但readFile只能用于字符串,而且在读取时我们无法知道要读取的字节数,除非我们将dataBytes(第一个)变量放在结构体中,以便我们知道要读取多少字节。

由于字符串无法转换为TestData类型,我还没有尝试。这里有一个包含(float, float)元组的问题,通过流解决了,但那个数据结构相对简单。


<details>
<summary>英文:</summary>

Assume I&#39;ve got this data type:

```Nim

type
  TODO* = tuple
    atTime: float
    item: string

type
  TestData* = tuple
    timeAdded: float
    who: string
    todo: seq[TODO]
    isDone: bool


var data: TestData
# code which sets and adds stuff in/to data

So the length will vary because of the seq.
Is there a direct way to save/load this data ?
Something like:
writeFile("testdata.dat", data) and later on readFile("testdata.dat", data) ?
I only find string and openArray for writeFile. But readFile is only for a string plus when reading we won't know the number of bytes to read, unless we make dataBytes (the first) variable in the struct, so we know how many bytes to read.

Haven't tried because the string won't be convertible to the TestData type. There was a question here with tuples of (float, float), solved with streams, but that data structure was simple(r).

答案1

得分: 2

问题在于,像字符串或序列这样的数据类型是值类型,它们包含指向实际堆分配数据的(隐藏的)指针。因此,再次包含字符串或序列的数据类型不是简单的二进制数据块,无法通过单个操作写入磁盘。对于字符串和具有普通对象类型作为基本类型的序列,如seq[float],我们可以写入一个单一的二进制数据块。在这种情况下,对于一个序列,我们可以使用addr myseq[0]作为数据块的起始位置,而myseq.len*sizeof(typeof(myseq[0]))将给出数据块的大小。当然,在读取该数据块之前,我们需要分配数据缓冲区,例如使用类似mySeq = newSeq[myBaseType](blobSizeOnDisk div sizeof(mybasetype))的方式。这只是为了让您对问题有所了解,我知道这对您实际的问题并没有真正帮助。对于非平凡数据的序列化,Nim有许多库,如JSON序列化。只要元素类型在编译时是静态且已知的,这些库就可以处理大多数嵌套数据类型。据我所知,当我们使用ref对象的序列,并且ref对象在运行时具有不同的实际类型时,所有库都会出现一些问题。如果您不想使用人类可读的JSON(或YAML或TOML)格式,您可以搜索术语"二进制序列化"。我认为Nim有一些用于此目的的库,但是我从未使用过其中的任何一个,抱歉。

英文:

The problem is, that data types like strings or sequences are value types, that contain a (hidden) pointer to the actual heap-allocated data. So data types, that contain again strings or sequences, are not simple blobs, which can be written to disk with a single operation. For strings, and for sequences that have plain object types as base types, like seq[float], we could write a single binary blob. In that case, for a seq, we could use addr myseq[0] as start of the blob, and myseq.len*sizeof(typeof(myseq[0])) would give us the size of the blob. Of course, before reading that blob, we would have to allocate the data buffer, e.g. with something like mySeq = newSeq[myBaseType](blobSizeOnDisk div sizeof(mybasetype)). This is just for you to get a feeling for the problem, I know that it is not really helpful for your actual issue. For the serialization of non-trivial data, Nim has many libraries like JSON serialization. These libs can handle most nested data types, as long as the element types are static and known at compile time. As far as I know, all libs have some problems when we use sequences of ref objects, and the ref objects have various actual types as runtime. When you do not want to use human-readable JSON (or YAML or TOML) format, you may search for the term "binary serialization". I think Nim has a few libs for that, but I never used one of them, sorry.

huangapple
  • 本文由 发表于 2023年6月9日 05:53:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/76435931.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定