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

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

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

问题

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

以下是翻译好的代码:

  1. package main
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. )
  7. func main() {
  8. var jsonBlob = []byte(`[
  9. {"Name": "Platypus", "Order": "Monotremata"},
  10. {"Name": "Quoll", "Order": "Dasyuromorphia"}
  11. ]`)
  12. //var b bytes.Buffer
  13. b := *bytes.NewBuffer(make([]byte, 20))
  14. b.Write(jsonBlob)
  15. fmt.Println(b.String())
  16. var dat interface{}
  17. err := json.Unmarshal(b.Bytes(), &dat)
  18. if err != nil {
  19. fmt.Println("error:", err)
  20. }
  21. fmt.Printf("%+v", dat)
  22. }

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

  1. [
  2. {"Name": "Platypus", "Order": "Monotremata"},
  3. {"Name": "Quoll", "Order": "Dasyuromorphia"}
  4. ]
  5. [map[Name:Platypus Order:Monotremata] map[Name:Quoll Order:Dasyuromorphia]]
  6. 程序已退出。
  7. 使用`bytes.NewBuffer`运行的输出结果:

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

  1. <details>
  2. <summary>英文:</summary>
  3. 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.
  4. package main
  5. import (
  6. &quot;bytes&quot;
  7. &quot;encoding/json&quot;
  8. &quot;fmt&quot;
  9. )
  10. func main() {
  11. var jsonBlob = []byte(`[
  12. {&quot;Name&quot;: &quot;Platypus&quot;, &quot;Order&quot;: &quot;Monotremata&quot;},
  13. {&quot;Name&quot;: &quot;Quoll&quot;, &quot;Order&quot;: &quot;Dasyuromorphia&quot;}
  14. ]`)
  15. //var b bytes.Buffer
  16. b := *bytes.NewBuffer(make([]byte, 20))
  17. b.Write(jsonBlob)
  18. fmt.Println(b.String())
  19. var dat interface{}
  20. err := json.Unmarshal(b.Bytes(), &amp;dat)
  21. if err != nil {
  22. fmt.Println(&quot;error:&quot;, err)
  23. }
  24. fmt.Printf(&quot;%+v&quot;, dat)
  25. }
  26. Output for Run with bytes.Buffer
  27. [
  28. {&quot;Name&quot;: &quot;Platypus&quot;, &quot;Order&quot;: &quot;Monotremata&quot;},
  29. {&quot;Name&quot;: &quot;Quoll&quot;, &quot;Order&quot;: &quot;Dasyuromorphia&quot;}
  30. ]
  31. [map[Name:Platypus Order:Monotremata] map[Name:Quoll Order:Dasyuromorphia]]
  32. Program exited.
  33. Output for Run with bytes.NewBuffer
  34. [
  35. {&quot;Name&quot;: &quot;Platypus&quot;, &quot;Order&quot;: &quot;Monotremata&quot;},
  36. {&quot;Name&quot;: &quot;Quoll&quot;, &quot;Order&quot;: &quot;Dasyuromorphia&quot;}
  37. ]
  38. error: invalid character &#39;\x00&#39; looking for beginning of value
  39. &lt;nil&gt;
  40. </details>
  41. # 答案1
  42. **得分**: 11
  43. [NewBuffer](https://godoc.org/bytes#NewBuffer) 函数使用参数作为缓冲区的初始内容。调用 `make([]byte, 20)` 返回一个包含 20 个零字节的字节切片。在 `b.Write(jsonBlob)` 之后,缓冲区的内容是 20 个零字节,后面跟着 JSON 文本。
  44. 在程序中添加 `fmt.Printf("%q\n", b.String())` 来查看缓冲区的内容。
  45. &lt;kbd&gt;[添加 printf 的 playground 示例](https://play.golang.org/p/4xnF5Uo4Uc)&lt;/kbd&gt;
  46. JSON 解析器对第一个零字节抱怨。
  47. 如果你的目标是设置内部缓冲区的大小,请使用以下代码:
  48. b := bytes.NewBuffer(make([]byte, 0, 20))
  49. 调用 `make([]byte, 0, 20)` 返回一个长度为零、容量为 20 的切片。
  50. &lt;kbd&gt;[零长度切片的 playground 示例](https://play.golang.org/p/f7jz8HDwOc)&lt;/kbd&gt;
  51. 类型为 `byte.Buffer` 的变量开始时为空缓冲区。
  52. 如果你的目标是限制读取的数据量,请使用 [io.LimitedReader](https://godoc.org/io#LimitedReader)。例如:
  53. f, err := os.Open("filename")
  54. if err != nil {
  55. // 处理错误
  56. }
  57. defer f.Close()
  58. err := json.NewDecoder(&io.LimitedReader{N: 20, R: f}).Decode(&dat)
  59. if err != nil {
  60. // 处理错误。如果文件被截断,将得到解析错误。
  61. }
  62. <details>
  63. <summary>英文:</summary>
  64. 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.
  65. Add `fmt.Printf(&quot;%q\n&quot;, b.String())` to the program to view the contents of the buffer.
  66. &lt;kbd&gt;[playground example with printf added](https://play.golang.org/p/4xnF5Uo4Uc)&lt;/kbd&gt;
  67. The JSON parser complains about the first zero byte.
  68. If your goal is to set the size of the internal buffer, use this code:
  69. b := bytes.NewBuffer(make([]byte, 0, 20))
  70. The call `make([]byte, 0, 20)` returns a zero length slice with capacity 20.
  71. &lt;kbd&gt;[playground example with zero length slice](https://play.golang.org/p/f7jz8HDwOc)&lt;/kbd&gt;
  72. A variable of type `byte.Buffer` starts as the empty buffer.
  73. If your goal is to limit the amount of data read, then use [io.LimitedReader](https://godoc.org/io#LimitedReader). For example:
  74. f, err := os.Open(&quot;filename&quot;)
  75. if err != nil {
  76. // handle error
  77. }
  78. defer f.Close()
  79. err := json.NewDecoder(&amp;io.LimitedReader{N: 20, R: f}).Decode(&amp;dat)
  80. if err != nil {
  81. // handle error. Will get parse error if file is truncated.
  82. }
  83. </details>
  84. # 答案2
  85. **得分**: 3
  86. 阅读[这个][1]:
  87. &gt; func NewBuffer
  88. &gt;
  89. &gt; func NewBuffer(buf []byte) *Buffer NewBuffer使用buf作为其初始内容创建并初始化一个新的Buffer。它旨在准备一个Buffer来读取现有数据。它也可以用于调整写入的内部缓冲区的大小。为此,buf应该具有所需的容量,但长度为零。
  90. &gt;
  91. &gt; 在大多数情况下,new(Buffer)(或只是声明一个Buffer变量)就足以初始化一个Buffer。
  92. 在`b.Write(jsonBlob)`之后,因为您的缓冲区没有长度为零(`make([]byte, 20)`创建了一个长度为20的切片),所以`b.Bytes()`是您分配的20个字节加上json内容。然后当您执行`Unmarshal`时,json解析器将在开头看到20个零,当然会报错。
  93. [1]: https://golang.org/pkg/bytes/#NewBuffer
  94. <details>
  95. <summary>英文:</summary>
  96. read [this][1]:
  97. &gt; func NewBuffer
  98. &gt;
  99. &gt; func NewBuffer(buf []byte) *Buffer NewBuffer creates and initializes a
  100. &gt; new Buffer using buf as its initial contents. It is intended to
  101. &gt; prepare a Buffer to read existing data. It can also be used to size
  102. &gt; the internal buffer for writing. To do that, buf should have the
  103. &gt; desired capacity but a length of zero.
  104. &gt;
  105. &gt; In most cases, new(Buffer) (or just declaring a Buffer variable) is
  106. &gt; sufficient to initialize a Buffer.
  107. 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.
  108. [1]: https://golang.org/pkg/bytes/#NewBuffer
  109. </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:

确定