在Go语言中将JSON []byte作为字符串进行编组

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

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"
}

huangapple
  • 本文由 发表于 2016年4月7日 09:20:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/36465065.html
匿名

发表评论

匿名网友

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

确定