我正在寻找有关json marshal的信息。我先解释一下情况。
我正在为物联网设备开发应用程序。该应用程序将MQTT数据包内的JSON发送给我们的代理。设备如何使用SIM进行数据连接我需要将数据包的字节数减少到最小。
目前,JSON具有这种结构
{
"d": 1524036831
"p": "important message"
}
字段d
是时间戳,p
是有效负载。
当应用程序发送此JSON时,它有40个字节。但是如果d
是1000,那么,JSON将是34个字节。因此,编组将字段d
转换为uint32,并将其转换为数字的ASCII表示,然后发送字符串。
我想要的是将此字段作为true int或uint发送。我想说,1524036831
是int32
,4个字节,与1000
相同。因此,通过此更改,我可以将数据包大小减少一些字节,并且数量可以增长到32位。
我阅读了json.Marshal的文档,但我没有找到任何相关内容。
我找到了一个"解决方案"但我客人不是很漂亮,但做的工作。我想要另一种意见。
丑陋的解决方案(对我来说)
package main
import (
"encoding/binary"
"encoding/json"
"fmt"
)
type test struct {
Data uint32 `json:"d"`
Payload string `json:"p"`
}
type testB struct {
Data []byte `json:"d"`
Payload string `json:"p"`
}
func main() {
fmt.Println("TEST with uin32")
d := []test{test{Data: 5, Payload: "Important Message"}, test{Data: 10, Payload: "Important Message"}, test{Data: 1000, Payload: "Important Message"}, test{Data: 1524036831, Payload: "Important Message"}}
for _, i := range d {
j, _ := json.Marshal(i)
fmt.Println(string(j))
fmt.Println("All:", len(j))
fmt.Println("-----------")
}
fmt.Println("\nTEST with []Byte")
d1 := []testB{testB{Data: make([]byte, 4), Payload: "Important Message"}, testB{Data: make([]byte, 4), Payload: "Important Message"}, testB{Data: make([]byte, 4), Payload: "Important Message"}, testB{Data: make([]byte, 4), Payload: "Important Message"}}
binary.BigEndian.PutUint32(d1[0].Data, 5)
binary.BigEndian.PutUint32(d1[1].Data, 20)
binary.BigEndian.PutUint32(d1[2].Data, 1000)
binary.BigEndian.PutUint32(d1[3].Data, 1524036831)
for _, i := range d1 {
j, _ := json.Marshal(i)
fmt.Println(string(j))
fmt.Println(len(j))
fmt.Println("-----------")
}
}
答案 0 :(得分:0)
重新整理我的评论:JSON是一种文本格式,文本格式不是为了生成小消息而设计的。特别是在JSON中没有除十进制字符串之外的数字的表示。
在大于10的基数中编码数字会减少足够大数量的邮件大小。
您可以通过删除前导零字节和使用base64.RawStdEncoding(省略填充字符)进行编码来减少“丑陋”代码产生的消息大小。这样做可以支付数字> = 1e6。
如果你把这一切都放在一个自定义类型中,它就会变得更好用:
package main
import (
"bytes"
"encoding/base64"
"encoding/binary"
"encoding/json"
"fmt"
)
type IntB64 uint32
func (n IntB64) MarshalJSON() ([]byte, error) {
b := make([]byte, 4)
binary.BigEndian.PutUint32(b, uint32(n))
b = bytes.TrimLeft(b, string(0))
// All characters in the base64 alphabet need not be escaped, so we don't
// have to call json.Marshal here.
l := base64.RawStdEncoding.EncodedLen(len(b)) + 2
j := make([]byte, l)
base64.RawStdEncoding.Encode(j[1:], b)
j[0], j[l-1] = '"', '"'
return j, nil
}
func main() {
enc(1) // "AQ"
enc(1000) // "A+g"
enc(1e6 - 1) // "D0I/"
enc(1e6) // "D0JA"
enc(1524036831) // "Wtb03w"
}
func enc(n int64) {
b, _ := json.Marshal(IntB64(n))
fmt.Printf("%10d %s\n", n, string(b))
}