为什么json.Encoder会添加额外的行?

时间:2016-03-30 21:16:54

标签: json go

json.Encoder似乎与json.Marshal略有不同。具体来说,它在编码值的末尾添加一个新行。知道为什么会这样吗?对我来说这看起来像个错误。

package main

import "fmt"
import "encoding/json"
import "bytes"

func main() {
    var v string
    v = "hello"
    buf := bytes.NewBuffer(nil)
    json.NewEncoder(buf).Encode(v)
    b, _ := json.Marshal(&v)

    fmt.Printf("%q, %q", buf.Bytes(), b)
}

此输出

"\"hello\"\n", "\"hello\""

Try it in the Playground

3 个答案:

答案 0 :(得分:5)

因为他们在使用Encoder.Encode时明确添加了新的字符。这是该func的源代码,它实际上表明它在文档中添加了换行符(参见注释,这是文档):

https://golang.org/src/encoding/json/stream.go?s=4272:4319#L173

// Encode writes the JSON encoding of v to the stream,
// followed by a newline character.
//
// See the documentation for Marshal for details about the
// conversion of Go values to JSON.
func (enc *Encoder) Encode(v interface{}) error {
    if enc.err != nil {
        return enc.err
    }
    e := newEncodeState()
    err := e.marshal(v)
    if err != nil {
        return err
    }

    // Terminate each value with a newline.
    // This makes the output look a little nicer
    // when debugging, and some kind of space
    // is required if the encoded value was a number,
    // so that the reader knows there aren't more
    // digits coming.
    e.WriteByte('\n')

    if _, err = enc.w.Write(e.Bytes()); err != nil {
        enc.err = err
    }
    encodeStatePool.Put(e)
    return err
}

现在,为什么Go开发人员除了“使输出看起来有点好”之外还做了什么呢?一个答案:

go json Encoder针对流进行了优化(例如json数据的MB / GB / PB)。通常,在流式传输时,您需要一种方法来消除流完成的时间。对于Encoder.Encode(),这是一个\n换行符。当然,你当然可以写入缓冲区。但是你也可以写一个io.Writer来传输v的块。

这与使用json.Marshal相反,如果您的输入来自不受信任(且未知的有限)来源(例如,ajax POST方法到您的Web服务 - 如果有人发布了100MB json,那么通常不鼓励使用json.Marshal文件?)。并且,Marshal将是json的最终完整集合 - 例如你不希望将几个\gb个条目连在一起。您可以使用Encoder.Encode()来构建一个大型集合并写入缓冲区,流,文件,io.Writer等。

每当怀疑它是否是一个bug时,我总是查找源代码 - 这是Go的优点之一,它的源代码和编译器只是纯粹的Go。在[n] vim中,我使用/usr/lib/kscreenlocker_greet --testingmy .vimrc settings的浏览器中打开源定义。

答案 1 :(得分:0)

Encoder写入值流。额外的空格是值之间的分隔符。

答案 2 :(得分:0)

您可以通过反向流擦除换行符:

f, _ := os.OpenFile(fname, ...)
encoder := json.NewEncoder(f)
encoder.Encode(v)
f.Seek(-1, 1)
f.WriteString("other data ...")

他们应该让用户控制这种奇怪的行为:

  • 禁用它的构建选项
  • Encoder.SetEOF(eof string)
  • Encoder.SetIndent(prefix, indent, eof string)