5

我正在尝试读取由 mongodump 生成的集合转储。该文件有几千兆字节,所以我想逐步阅读它。

我可以用这样的方式读取第一个对象:

buf := make([]byte, 100000)
f, _ := os.Open(path)
f.Read(buf)

var m bson.M
bson.Unmarshal(buf, &m)

但是我不知道消耗了多少buf,所以我不知道如何阅读下一个。

这可以用mgo吗?

4

4 回答 4

4

单独使用 mgobson.Unmarshal()是不够的——该函数旨在获取一个[]byte表示单个文档,并将其解组为一个值。

您将需要一个可以从转储文件中读取下一个完整文档的函数,然后您可以将结果传递给bson.Unmarshal().

将此与encoding/jsonor进行比较encoding/gob,如果mgo.bson有一个Reader类型从io.Reader.

无论如何,从mongodump 的源代码来看,转储文件看起来只是一系列 bson 文档,没有文件页眉/页脚或显式记录分隔符。

BSONTool::processFile显示了 mongorestore 如何读取转储文件。他们的代码读取 4 个字节以确定文档的长度,然后使用该大小读取文档的其余部分。确认大小前缀是bson 规范的一部分。

这是一个游乐场示例,展示了如何在 Go 中完成此操作:读取长度字段,读取文档的其余部分,解组,重复。

于 2014-06-13T11:20:16.803 回答
3

该方法File.Read返回读取的字节数。

文件读取

Read 从文件中读取最多 len(b) 个字节。它返回读取的字节数和错误(如果有)。EOF 由 err 设置为 io.EOF 的零计数发出信号。

因此,您可以通过简单地存储您读取的返回参数来获取读取的字节数:

n, err := f.Read(buf)
于 2014-06-13T06:58:40.970 回答
2

我设法用以下代码解决了它:

for len(buf) > 0 {
    var r bson.Raw
    var m userObject

    bson.Unmarshal(buf, &r)
    r.Unmarshal(&m)

    fmt.Println(m)

    buf = buf[len(r.Data):]
}
于 2014-06-16T09:18:31.647 回答
0

Niks Keets 的回答对我不起作用。不知何故len(r.Data)总是整个缓冲区长度。所以我提出了其他代码:

for len(buff) > 0 {
    messageSize := binary.LittleEndian.Uint32(buff)
    err = bson.Unmarshal(buff, &myObject)
    if err != nil {
        panic(err)
    }

    // Do your stuff

    buff = buff[messageSize:]
}

当然,您必须在缓冲区末尾处理截断的结构。就我而言,我可以将整个文件加载到内存中。

于 2018-03-06T14:01:35.700 回答