英文:
Marshaling JSON []byte as strings in Go
问题
我有一个包含字符串作为[]byte字段的结构体,我想将其编码为JSON。然而,生成的JSON包含了一个意外的字符串表示切片内容的方式。以下是我所指的示例:
package main
import (
"fmt"
"encoding/json"
)
type Msg struct {
Content []byte
}
func main() {
helloStr := "Hello"
helloSlc := []byte(helloStr)
fmt.Println(helloStr, helloSlc)
obj := Msg{helloSlc}
json, _ := json.Marshal(obj)
fmt.Println(string(json))
}
这将产生以下输出:
Hello [72 101 108 108 111]
{"Content":"SGVsbG8="}
json.Marshal()方法对[]byte编码的字符串执行了什么样的转换?如何生成一个包含原始字符串内容的JSON {"Content":"Hello"}?
英文:
I have a struct containing strings as []byte fields which I'd like to encode into JSON. However, the generated JSON contains a non expected string representation of the slice contents. Here is an example of what I refer:
package main
import (
"fmt"
"encoding/json"
)
type Msg struct {
Content []byte
}
func main() {
helloStr := "Hello"
helloSlc := []byte(helloStr)
fmt.Println(helloStr, helloSlc)
obj := Msg{helloSlc}
json, _ := json.Marshal(obj)
fmt.Println(string(json))
}
This produces the following output:
Hello [72 101 108 108 111]
{"Content":"SGVsbG8="}
What kind of conversion is the json.Marshal() method performing to the []byte encoded string. How can I generate a JSON with the original content of my string {"Content":"Hello"}?
答案1
得分: 20
一个[]byte
被编组为base64编码的字符串。根据文档:
> 数组和切片值被编码为JSON数组,除了[]byte
被编码为base64编码的字符串,而nil切片被编码为null JSON对象。
这些值在解组时被正确解码。
之所以这样做的原因是JSON没有原生的表示原始字节的方式。详细解释请参见这个问题。
英文:
A []byte
is marshalled as base64 encoded string. From the documentation:
> Array and slice values encode as JSON arrays, except that []byte
encodes as a base64-encoded string, and a nil slice encodes as the null JSON object.
These values are decoded properly when unmarshalled.
The reason why this is done is that JSON does not have a native representation for raw bytes. See this question for a detailed explanation.
答案2
得分: 5
我遇到了同样的问题,即使这是一个相当旧的问题,并且已经有了答案,还有另一种选择。
如果你使用json.RawMessage
(它在内部是一个[]byte
)作为类型,而不是[]byte
,那么编组就会按预期将其转换为一个JSON字符串。
英文:
I came a cross the same thing and even if this is a rather old question and already answered there is another option.
If you use json.RawMessage
(which internaly is a []byte) as a type instead of []byte
the Marshaling works into a Json String as expected.
答案3
得分: 0
你可以使用第三方库来实现你想要的功能。
package main
import (
"fmt"
"strconv"
"strings"
"time"
"unsafe"
jsoniter "github.com/json-iterator/go"
)
func main() {
err := test()
if err != nil {
panic(err)
}
}
func test() error {
jsoniter.RegisterTypeEncoder("[]uint8", &uint8Enc{})
var a struct {
A []byte `json:"a"`
B []byte `json:"b"`
}
a.A = []byte{'1', 1, 2, 3, '9'}
a.B = []byte(time.Now().String())
s, err := json.MarshalIndent(a, "", " ")
if err != nil {
return err
}
fmt.Println(string(s))
return nil
}
var json = jsoniter.ConfigCompatibleWithStandardLibrary
type uint8Enc struct{}
func (ue *uint8Enc) IsEmpty(ptr unsafe.Pointer) bool {
data := *((*[]uint8)(ptr))
return len(data) == 0
}
func (ue *uint8Enc) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
var (
data = *((*[]uint8)(ptr))
sb strings.Builder
)
const hexTable = "0123456789abcdef"
for _, v := range data {
if strconv.IsPrint(rune(v)) {
sb.WriteByte(v)
} else {
sb.WriteString(`\x`)
sb.WriteByte(hexTable[v>>4])
sb.WriteByte(hexTable[v&0x0f])
}
}
stream.WriteString(sb.String())
}
结果如下所示
{
"a": "1\x01\x02\x039",
"b": "2023-06-05 09:15:38.551518 +0800 CST m=+0.003193401"
}
英文:
You can use a third party library to achieve what you want
package main
import (
"fmt"
"strconv"
"strings"
"time"
"unsafe"
jsoniter "github.com/json-iterator/go"
)
func main() {
err := test()
if err != nil {
panic(err)
}
}
func test() error {
jsoniter.RegisterTypeEncoder("[]uint8", &uint8Enc{})
var a struct {
A []byte `json:"a"`
B []byte `json:"b"`
}
a.A = []byte{'1', 1, 2, 3, '9'}
a.B = []byte(time.Now().String())
s, err := json.MarshalIndent(a, "", " ")
if err != nil {
return err
}
fmt.Println(string(s))
return nil
}
var json = jsoniter.ConfigCompatibleWithStandardLibrary
type uint8Enc struct{}
func (ue *uint8Enc) IsEmpty(ptr unsafe.Pointer) bool {
data := *((*[]uint8)(ptr))
return len(data) == 0
}
func (ue *uint8Enc) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
var (
data = *((*[]uint8)(ptr))
sb strings.Builder
)
const hexTable = "0123456789abcdef"
for _, v := range data {
if strconv.IsPrint(rune(v)) {
sb.WriteByte(v)
} else {
sb.WriteString(`\x`)
sb.WriteByte(hexTable[v>>4])
sb.WriteByte(hexTable[v&0x0f])
}
}
stream.WriteString(sb.String())
}
The result is as follows
{
"a": "1\\x01\\x02\\x039",
"b": "2023-06-05 09:15:38.551518 +0800 CST m=+0.003193401"
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论