user1283776 user1283776 - 5 months ago 11
JSON Question

Size in bits of object encoded to JSON?

I have an object. I encode the object to json using

json.Encoder
.

How can I measure the size of the json string in either bits?

Answer

io.Writer and json.Encoder does not expose nor maintain number of written bytes.

One way would be to first marshal the value using json.Marshal() into a []byte whose length we can get by using the builtin len() function. After that you have to manually write the byte slice to your output. For small types, this is not a problem, but it may be undesirable for large structs / values. Also there is unnecessary work marshalling it, getting its length and writing the slice manually.

A much better way is to extend the functionality of any writers to manage the written bytes, using embedding:

type CounterWr struct {
    io.Writer
    Count int
}

func (cw *CounterWr) Write(p []byte) (n int, err error) {
    n, err = cw.Writer.Write(p)
    cw.Count += n
    return
}

This CounterWr type automatically manages the number of written bytes in its Count field which you can check / examine at any time.

Now you create a value of our CounterWr passing the io.Writer that you currently use, and then pass this CounterWr value to json.NewEncoder(), and you can access number of written bytes from CounterWr.Count directly.

Example usage:

type Something struct {
    S string
    I int
}


buf := &bytes.Buffer{}

// Any writer, not just a buffer!
var out io.Writer = buf
cw := &CounterWr{Writer: out}

s := Something{"hello", 4}
if err := json.NewEncoder(cw).Encode(s); err != nil {
    panic(err)
}

fmt.Printf("Count: %d bytes, %d bits\n", cw.Count, cw.Count*8)
fmt.Printf("Verif: %d bytes, %d bits\n", buf.Len(), buf.Len()*8)

For verification purposes we're also printing the length of the bytes.Buffer we used as our output (CounterWr.Count and Buffer.Len() should match).

Output:

Count: 20 bytes, 160 bits
Verif: 20 bytes, 160 bits

Try it on the Go Playground.

Notes:

If you encode other values too, cw.Count will be the number of total bytes of course (and not just that of the last value). If you want to get the size of the last encoded value only, store cw.Count before calling Encoder.Encode(), and calculate the difference to the count you get after encoding it. Or simply set cw.Count to 0 before encoding (yes, you can also change that field):

cw.Count = 0