使用`bytes.Buffer`和`*bytes.NewBuffer`在`json.Unmarshal`中的区别是什么?

huangapple go评论84阅读模式
英文:

Difference in json.Unmarshal when using bytes.Buffer vs using *bytes.NewBuffer

问题

我正在查看bytes包。如果我使用bytes.Buffer定义一个缓冲区,那么下面的代码可以正常工作并输出结果。然而,如果我尝试创建一个具有特定容量的缓冲区,然后再尝试相同的代码,就会出现错误:错误:无效字符'\x00',寻找值的开头。不确定如何修复它。

以下是翻译好的代码:

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]]
程序已退出。

使用`bytes.NewBuffer`运行的输出结果:

[
{"Name": "Platypus", "Order": "Monotremata"},
{"Name": "Quoll", "Order": "Dasyuromorphia"}
]
错误:无效字符'\x00',寻找值的开头


<details>
<summary>英文:</summary>

I was looking at the bytes package. If I define a buffer using bytes.Buffer then the code below works and i get an output. However if I try create a buffer with a certain capacity and then try the same code it fails with the error error: invalid character &#39;\x00&#39; looking for beginning of value. Not sure how to fix it. 

    package main
    
    import (
        &quot;bytes&quot;
        &quot;encoding/json&quot;
        &quot;fmt&quot;
    )
    
    func main() {
        var jsonBlob = []byte(`[
            {&quot;Name&quot;: &quot;Platypus&quot;, &quot;Order&quot;: &quot;Monotremata&quot;},
                {&quot;Name&quot;: &quot;Quoll&quot;,    &quot;Order&quot;: &quot;Dasyuromorphia&quot;}
                ]`)
    
        //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(), &amp;dat)
        if err != nil {
            fmt.Println(&quot;error:&quot;, err)
        }   
        fmt.Printf(&quot;%+v&quot;, dat)
    }

Output for Run with bytes.Buffer 

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

Output for Run with bytes.NewBuffer

    [
    		{&quot;Name&quot;: &quot;Platypus&quot;, &quot;Order&quot;: &quot;Monotremata&quot;},
    		{&quot;Name&quot;: &quot;Quoll&quot;,    &quot;Order&quot;: &quot;Dasyuromorphia&quot;}
    	]
    error: invalid character &#39;\x00&#39; looking for beginning of value
    &lt;nil&gt;

</details>


# 答案1
**得分**: 11

[NewBuffer](https://godoc.org/bytes#NewBuffer) 函数使用参数作为缓冲区的初始内容。调用 `make([]byte, 20)` 返回一个包含 20 个零字节的字节切片。在 `b.Write(jsonBlob)` 之后,缓冲区的内容是 20 个零字节,后面跟着 JSON 文本。

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

&lt;kbd&gt;[添加 printf 的 playground 示例](https://play.golang.org/p/4xnF5Uo4Uc)&lt;/kbd&gt;

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

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

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

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

&lt;kbd&gt;[零长度切片的 playground 示例](https://play.golang.org/p/f7jz8HDwOc)&lt;/kbd&gt;

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

如果你的目标是限制读取的数据量,请使用 [io.LimitedReader](https://godoc.org/io#LimitedReader)。例如:

    f, err := os.Open("filename")
    if err != nil {
       // 处理错误
    }
    defer f.Close()
    err := json.NewDecoder(&io.LimitedReader{N: 20, R: f}).Decode(&dat)
    if err != nil {
        // 处理错误。如果文件被截断,将得到解析错误。
    }

<details>
<summary>英文:</summary>

The [NewBuffer](https://godoc.org/bytes#NewBuffer) function uses the argument as the initial contents of the buffer. The call `make([]byte, 20)` returns a byte slice containing 20 zero bytes. The contents of the buffer after `b.Write(jsonBlob)` is 20 zero bytes followed by the JSON text.  

Add `fmt.Printf(&quot;%q\n&quot;, b.String())` to the program to view the contents of the buffer.

&lt;kbd&gt;[playground example with printf added](https://play.golang.org/p/4xnF5Uo4Uc)&lt;/kbd&gt;

The JSON parser complains about the first zero byte. 

If your goal is to set the size of the internal buffer, use this code:

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

The call `make([]byte, 0, 20)` returns a zero length slice with capacity 20.

&lt;kbd&gt;[playground example with zero length slice](https://play.golang.org/p/f7jz8HDwOc)&lt;/kbd&gt;

A variable of type `byte.Buffer` starts as the empty buffer.

If your goal is to limit the amount of data read, then use [io.LimitedReader](https://godoc.org/io#LimitedReader). For example:

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


</details>



# 答案2
**得分**: 3

阅读[这个][1]:

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

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

  [1]: https://golang.org/pkg/bytes/#NewBuffer

<details>
<summary>英文:</summary>

read [this][1]:

&gt; func NewBuffer
&gt; 
&gt; func NewBuffer(buf []byte) *Buffer NewBuffer creates and initializes a
&gt; new Buffer using buf as its initial contents. It is intended to
&gt; prepare a Buffer to read existing data. It can also be used to size
&gt; the internal buffer for writing. To do that, buf should have the
&gt; desired capacity but a length of zero.
&gt; 
&gt; In most cases, new(Buffer) (or just declaring a Buffer variable) is
&gt; sufficient to initialize a Buffer.

After `b.Write(jsonBlob)`, because your buffer din&#39;t have a length of zero(`make([]byte, 20)` creates a 20-length slice), so that `b.Bytes()` is 20 bytes you allocated plus the json content. Then when you do `Unmarshal`, the json parser will see 20 zeros in the beginning, of course it complains.

  [1]: https://golang.org/pkg/bytes/#NewBuffer

</details>



huangapple
  • 本文由 发表于 2017年3月8日 09:08:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/42661206.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定