英文:
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 '\x00' looking for beginning of value. Not sure how to fix it.
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)
}
Output for Run with bytes.Buffer
[
{"Name": "Platypus", "Order": "Monotremata"},
{"Name": "Quoll", "Order": "Dasyuromorphia"}
]
[map[Name:Platypus Order:Monotremata] map[Name:Quoll Order:Dasyuromorphia]]
Program exited.
Output for Run with bytes.NewBuffer
[
{"Name": "Platypus", "Order": "Monotremata"},
{"Name": "Quoll", "Order": "Dasyuromorphia"}
]
error: invalid character '\x00' looking for beginning of value
<nil>
</details>
# 答案1
**得分**: 11
[NewBuffer](https://godoc.org/bytes#NewBuffer) 函数使用参数作为缓冲区的初始内容。调用 `make([]byte, 20)` 返回一个包含 20 个零字节的字节切片。在 `b.Write(jsonBlob)` 之后,缓冲区的内容是 20 个零字节,后面跟着 JSON 文本。
在程序中添加 `fmt.Printf("%q\n", b.String())` 来查看缓冲区的内容。
<kbd>[添加 printf 的 playground 示例](https://play.golang.org/p/4xnF5Uo4Uc)</kbd>
JSON 解析器对第一个零字节抱怨。
如果你的目标是设置内部缓冲区的大小,请使用以下代码:
b := bytes.NewBuffer(make([]byte, 0, 20))
调用 `make([]byte, 0, 20)` 返回一个长度为零、容量为 20 的切片。
<kbd>[零长度切片的 playground 示例](https://play.golang.org/p/f7jz8HDwOc)</kbd>
类型为 `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("%q\n", b.String())` to the program to view the contents of the buffer.
<kbd>[playground example with printf added](https://play.golang.org/p/4xnF5Uo4Uc)</kbd>
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.
<kbd>[playground example with zero length slice](https://play.golang.org/p/f7jz8HDwOc)</kbd>
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("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.
}
</details>
# 答案2
**得分**: 3
阅读[这个][1]:
> func NewBuffer
>
> func NewBuffer(buf []byte) *Buffer NewBuffer使用buf作为其初始内容创建并初始化一个新的Buffer。它旨在准备一个Buffer来读取现有数据。它也可以用于调整写入的内部缓冲区的大小。为此,buf应该具有所需的容量,但长度为零。
>
> 在大多数情况下,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]:
> func NewBuffer
>
> func NewBuffer(buf []byte) *Buffer NewBuffer creates and initializes a
> new Buffer using buf as its initial contents. It is intended to
> prepare a Buffer to read existing data. It can also be used to size
> the internal buffer for writing. To do that, buf should have the
> desired capacity but a length of zero.
>
> In most cases, new(Buffer) (or just declaring a Buffer variable) is
> sufficient to initialize a Buffer.
After `b.Write(jsonBlob)`, because your buffer din'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>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论