簡體   English   中英

在 go 中將 protobuf 消息順序寫入文件

[英]Sequentially write protobuf messages to a file in go

我有大量類似的對象(大約數百 GB),我需要對其進行序列化並按順序寫入文件,然后以相同的順序讀取它。 如何在golang的protobuf(gogo proto)中做到這一點? Gob 有一個可以寫入 io.Writer 的編碼器,但 protobuf 沒有類似的東西。 可能 protobuf 不是用於此目的的最佳選擇嗎? 我需要良好的性能和低內存分配。

如果您想將多條消息寫入單個文件或流,則由您來跟蹤一條消息的結束位置和下一條消息的開始位置。 Protocol Buffer 有線格式不是自定界的,因此 Protocol Buffer 解析器無法自行確定消息的結束位置。 解決這個問題最簡單的方法是在寫消息本身之前寫下每條消息的大小。 當您讀回消息時,您讀取大小,然后將字節讀入單獨的緩沖區,然后從該緩沖區解析。

來源

1. 編寫 Protobuf

將您的 protobuf 編組為[]byte並調用Write以及您要寫入的文件作為io.Writer 這寫的長度msgio.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

當你想讀出另一側的 protobufs 時,打開文件並將其作為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 _, err := io.ReadFull(r, msg); err != nil {
        return nil, err
    }

    return msg, err
}

Go 中的*os.File類型同時滿足io.Readerio.Writer接口,因此您不應該遇到任何問題。

感謝@Brits 指出這一點。

祝你好運!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM