我正在尝试读取由 mongodump 生成的集合转储。该文件有几千兆字节,所以我想逐步阅读它。
我可以用这样的方式读取第一个对象:
buf := make([]byte, 100000)
f, _ := os.Open(path)
f.Read(buf)
var m bson.M
bson.Unmarshal(buf, &m)
但是我不知道消耗了多少buf,所以我不知道如何阅读下一个。
这可以用mgo吗?
单独使用 mgobson.Unmarshal()
是不够的——该函数旨在获取一个[]byte
表示单个文档,并将其解组为一个值。
您将需要一个可以从转储文件中读取下一个完整文档的函数,然后您可以将结果传递给bson.Unmarshal()
.
将此与encoding/json
or进行比较encoding/gob
,如果mgo.bson
有一个Reader
类型从io.Reader
.
无论如何,从mongodump 的源代码来看,转储文件看起来只是一系列 bson 文档,没有文件页眉/页脚或显式记录分隔符。
BSONTool::processFile显示了 mongorestore 如何读取转储文件。他们的代码读取 4 个字节以确定文档的长度,然后使用该大小读取文档的其余部分。确认大小前缀是bson 规范的一部分。
这是一个游乐场示例,展示了如何在 Go 中完成此操作:读取长度字段,读取文档的其余部分,解组,重复。
该方法File.Read
返回读取的字节数。
Read 从文件中读取最多 len(b) 个字节。它返回读取的字节数和错误(如果有)。EOF 由 err 设置为 io.EOF 的零计数发出信号。
因此,您可以通过简单地存储您读取的返回参数来获取读取的字节数:
n, err := f.Read(buf)
我设法用以下代码解决了它:
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):]
}
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:]
}
当然,您必须在缓冲区末尾处理截断的结构。就我而言,我可以将整个文件加载到内存中。