JSON Marshal uint或int为整数

时间:2018-04-18 09:56:32

标签: json go marshalling

我正在寻找有关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发送。我想说,1524036831int32,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("-----------")
    }
}

Play

1 个答案:

答案 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))
}

更新了游乐场:https://play.golang.org/p/7Z03VE9roqN