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