【问题标题】:Difference in json.Unmarshal when using bytes.Buffer vs using *bytes.NewBuffer使用 bytes.Buffer 与使用 *bytes.NewBuffer 时 json.Unmarshal 的差异
【发布时间】:2017-03-08 01:08:30
【问题描述】:

我在看字节包。如果我使用 bytes.Buffer 定义一个缓冲区,那么下面的代码可以工作并且我得到一个输出。但是,如果我尝试创建一个具有一定容量的缓冲区,然后尝试相同的代码,它会失败并出现错误错误:invalid character '\x00' looking for beginning of value。不知道如何解决它。

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
)

func main() {
    var jsonBlob = []byte(`[
        {"Name": "Platypus", "Order": "Monotremata"},
            {"Name": "Quoll",    "Order": "Dasyuromorphia"}
            ]`)

    //var b bytes.Buffer
    b := *bytes.NewBuffer(make([]byte, 20))
    b.Write(jsonBlob)

    fmt.Println(b.String())

    var dat interface{}
    err := json.Unmarshal(b.Bytes(), &dat)
    if err != nil {
        fmt.Println("error:", err)
    }   
    fmt.Printf("%+v", dat)
}

使用 bytes.Buffer 运行的输出

[
        {"Name": "Platypus", "Order": "Monotremata"},
        {"Name": "Quoll",    "Order": "Dasyuromorphia"}
    ]
[map[Name:Platypus Order:Monotremata] map[Name:Quoll Order:Dasyuromorphia]]
Program exited.

使用 bytes.NewBuffer 运行的输出

[
        {"Name": "Platypus", "Order": "Monotremata"},
        {"Name": "Quoll",    "Order": "Dasyuromorphia"}
    ]
error: invalid character '\x00' looking for beginning of value
<nil>

【问题讨论】:

    标签: go


    【解决方案1】:

    NewBuffer 函数使用参数作为缓冲区的初始内容。调用 make([]byte, 20) 返回一个包含 20 个零字节的字节片。 b.Write(jsonBlob) 之后的缓冲区内容是 20 个零字节,后跟 JSON 文本。

    在程序中添加fmt.Printf("%q\n", b.String())可以查看缓冲区的内容。

    playground example with printf added

    JSON 解析器抱怨第一个零字节。

    如果您的目标是设置内部缓冲区的大小,请使用以下代码:

    b := bytes.NewBuffer(make([]byte, 0, 20))
    

    调用 make([]byte, 0, 20) 返回一个容量为 20 的零长度切片。

    playground example with zero length slice

    byte.Buffer 类型的变量作为空缓冲区开始。

    如果您的目标是限制读取的数据量,请使用io.LimitedReader。例如:

    f, err := os.Open("filename")
    if err != nil {
       // handle error
    }
    defer f.Close()
    err := json.NewDecoder(&io.LimitedReader{N: 20, R: f}).Decode(&dat)
    if err != nil {
        // handle error. Will get parse error if file is truncated. 
    }
    

    【讨论】:

    • 谢谢!有没有办法限制缓冲区不增长?由于尽管将容量设置为 20,但当大小增加时,缓冲区大小会增长直到溢出。我是否必须编写自己的 Write 方法才能做到这一点?或者有没有办法做到这一点,而不必编写我自己的自定义包装器,例如 eLitmus 博客中的包装器。 (参考elitmus.com/blog/technology/custom-capacity-buffers-in-go
    • 无法限制 bytes.Buffer 的大小。你能在更高的层次上描述你想要完成的事情吗?
    • 我试图将文件的内容读入缓冲区,然后解析内容。但是,如果由于文件大小太大而导致内存已满,那么我的应用程序将会崩溃。因此,我想先发制人地限制缓冲区大小并设置上限。这样当它达到上限时,我可以出错。
    • 使用io.LimitedReader,如更新答案中所述。
    【解决方案2】:

    阅读this:

    func 新缓冲区

    func NewBuffer(buf []byte) *Buffer NewBuffer 创建并初始化一个 new Buffer 使用 buf 作为其初始内容。它旨在 准备一个缓冲区来读取现有数据。也可以用来调整大小 用于写入的内部缓冲区。为此, buf 应该具有 所需的容量,但长度为零。

    在大多数情况下,new(Buffer)(或者只是声明一个 Buffer 变量)是 足以初始化一个 Buffer。

    b.Write(jsonBlob) 之后,因为您的缓冲区长度不为零(make([]byte, 20) 创建一个长度为 20 的切片),所以b.Bytes() 是您分配的 20 个字节加上 json 内容。然后当你做Unmarshal时,json解析器会在开头看到20个零,当然会报错。

    【讨论】:

    猜你喜欢
    • 2014-02-07
    • 1970-01-01
    • 1970-01-01
    • 2019-10-17
    • 2022-10-05
    • 1970-01-01
    • 2012-03-04
    • 2019-11-09
    • 2011-12-18
    相关资源
    最近更新 更多