我有大量相似的对象(大约数百GB),我需要对其进行序列化并依次写入文件,然后以相同的顺序读取它。如何在golang的protobuf(gogo proto)中做到这一点? Gob有一个可以写入io.Writer的编码器,但是protobuf没有类似的东西。可能不是protobuf并非为此目的的最佳选择?我需要良好的性能和较低的内存分配。
lovers_php 回答:依次将protobuf消息写入go中的文件
如果您想将多个消息写入单个文件或流,则它将 由您决定跟踪一条消息的结尾和下一条消息的结尾 开始。协议缓冲区连线格式不是自定界的,因此 协议缓冲区解析器无法确定消息在其何处结束 拥有。解决此问题的最简单方法是写下 每条消息,然后再编写消息本身。当您阅读 消息返回时,您读取大小,然后将字节读取到 单独的缓冲区,然后从该缓冲区进行解析。
1。编写Protobuf
将您的probubuf编组到[]byte
中,并与您要写入的文件Write
一起调用io.Writer
。在写msg
本身之前,这会将io.Writer
的长度写入msg
。
func Write(w io.Writer,msg []byte) error {
buf := make([]byte,4)
binary.LittleEndian.PutInt32(buf,Uint32(len(msg)))
if _,err := w.Write(buf); err != nil {
return err
}
if _,err := w.Write(msg); err != nil {
return err
}
}
2。阅读Protobuf
当您想读出另一侧的原型缓冲区时,请打开文件并将其作为io.Reader
传递。这将从文件中提取大小,然后将相应数量的字节读取到msg
缓冲区中并返回。
func Read(r io.Reader) ([]byte,error) {
buf := make([]byte,4)
if _,err := io.ReadFull(r,buf); err != nil {
return nil,err
}
size := binary.LittleEndian.Uint32(buf)
msg := make([]byte,size)
if _,msg); err != nil {
return nil,err
}
return msg,err
}
Go中的*os.File
类型同时满足io.Reader
和io.Writer
接口,因此您不会遇到任何问题。
@Brits指出了这一点。
祝你好运!