gpt4 book ai didi

serialization - 使用 Gob 以追加方式将日志写入文件

转载 作者:IT王子 更新时间:2023-10-29 00:44:53 27 4
gpt4 key购买 nike

是否可以使用 Gob 编码将结构串联附加到同一文件中?它适用于写作,但是当我不止一次地使用解码器阅读时,我遇到了:

extra data in buffer

所以我首先想知道这是否可行,或者我是否应该使用 JSON 之类的东西来逐行附加 JSON 文档。因为另一种方法是序列化一个 slice ,但再次将其作为一个整体读取会破坏追加的目的。

最佳答案

gob 软件包并非设计为以这种方式使用。 gob 流必须由单个 gob.Encoder 写入, 它也必须由单个 gob.Decoder 读取.

这是因为 gob package 不仅序列化你传递给它的值,它还传输数据来描述它们的类型:

A stream of gobs is self-describing. Each data item in the stream is preceded by a specification of its type, expressed in terms of a small set of predefined types.

这是编码器/解码器的状态——关于什么类型以及它们是如何传输的——后续的新编码器/解码器将不会(不能)分析“前面的”流来重建相同的状态并继续之前的编码器/解码器停止了。

当然,如果您创建单个 gob.Encoder ,您可以使用它来序列化任意数量的值。

您还可以创建 gob.Encoder并写入一个文件,然后创建一个新的 gob.Encoder , 并附加到同一个文件,但是您必须使用 2 gob.Decoder s 读取这些值,与编码过程完全匹配。

作为演示,我们来看一个例子。此示例将写入内存缓冲区 ( bytes.Buffer )。 2 个后续编码器将写入它,然后我们将使用 2 个后续解码器读取值。我们将写入此结构的值:

type Point struct {
X, Y int
}

为了简短、紧凑的代码,我使用了这个“错误处理程序”函数:

func he(err error) {
if err != nil {
panic(err)
}
}

现在是代码:

const n, m = 3, 2
buf := &bytes.Buffer{}

e := gob.NewEncoder(buf)
for i := 0; i < n; i++ {
he(e.Encode(&Point{X: i, Y: i * 2}))
}

e = gob.NewEncoder(buf)
for i := 0; i < m; i++ {
he(e.Encode(&Point{X: i, Y: 10 + i}))
}

d := gob.NewDecoder(buf)
for i := 0; i < n; i++ {
var p *Point
he(d.Decode(&p))
fmt.Println(p)
}

d = gob.NewDecoder(buf)
for i := 0; i < m; i++ {
var p *Point
he(d.Decode(&p))
fmt.Println(p)
}

输出(在 Go Playground 上尝试):

&{0 0}
&{1 2}
&{2 4}
&{0 10}
&{1 11}

请注意,如果我们只使用 1 个解码器来读取所有值(循环直到 i < n + m ,当迭代到达 n + 1 时,我们会收到您在问题中发布的相同错误消息,因为后续数据不是序列化的 Point ,而是新的 gob 流的开始。

所以如果你想坚持使用 gob做你想做的事情的包,你必须稍微修改,增强你的编码/解码过程。当使用新的编码器时,您必须以某种方式标记边界(因此在解码时,您将知道必须创建一个新的解码器来读取后续值)。

您可以使用不同的技术来实现这一点:

  • 您可以在继续写入值之前写出一个数字,一个计数,这个数字会告诉您使用当前编码器写入了多少个值。
  • 如果您不想或不能告诉当前编码器将写入多少个值,您可以选择写出一个特殊的 end-of-encoder 值,当您不这样做时' 使用当前编码器写入更多值。解码时,如果您遇到这种特殊的编码器结束值,您就会知道必须创建一个新的解码器才能读取更多值。

这里需要注意的几点:

  • gob如果只使用一个编码器,则包是最有效、最紧凑的,因为每次创建和使用新编码器时,都必须重新传输类型规范,从而导致更多开销,并使编码/解码过程较慢。
  • 您不能在数据流中查找,如果您从头开始读取整个文件直到您想要的值,您只能解码任何值。请注意,即使您使用其他格式(例如 JSON 或 XML),这在某种程度上也适用。

如果你想寻找功能,你需要单独管理一个 index 文件,它会告诉新的编码器/解码器从哪个位置开始,这样你就可以寻找到那个位置,创建一个新的解码器,并从那里开始读取值。

查看相关问题:Efficient Go serialization of struct to disk

关于serialization - 使用 Gob 以追加方式将日志写入文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43199137/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com