我想使用json.Encoder
对大量数据进行编码,而不会立即将所有数据加载到内存中。
// I want to marshal this
t := struct {
Foo string
// Bar is a stream of objects
// I don't want it all to be in memory at the same time.
Bar chan string
}{
Foo: "Hello World",
Bar: make(chan string),
}
// long stream of data
go func() {
for _, x := range []string{"one", "two", "three"} {
t.Bar <- x
}
close(t.Bar)
}()
我想也许json包有这个功能内置,但事实并非如此。
// error: json: unsupported type: chan string
if err := json.NewEncoder(os.Stdout).Encode(&t); err != nil {
log.Fatal(err)
}
我目前正在自己构建json字符串。
w := os.Stdout
w.WriteString(`{ "Foo": "` + t.Foo + `", "Bar": [`)
for x := range t.Bar {
_ = json.NewEncoder(w).Encode(x)
w.WriteString(`,`)
}
w.WriteString(`]}`)
有更好的方法吗?
如果json.Marshaler是这样的,那将是微不足道的。
type Marshaler interface {
MarshalJSON(io.Writer) error
}
答案 0 :(得分:2)
不幸的是,encoding/json
包还没有办法做到这一点。你现在正在做什么(手动)是最好的方法,而无需修改内置包。
如果您要修补encoding/json
,可以修改encoding/json/encode.go
reflectValueQuoted
功能
您可能希望专注于数组案例(Slice有fallthrough
):
// Inside switch:
case reflect.Array:
e.WriteByte('[')
n := v.Len()
for i := 0; i < n; i++ {
if i > 0 {
e.WriteByte(',')
}
e.reflectValue(v.Index(i))
}
e.WriteByte(']')
我假设你想以同样的方式对待频道。它看起来像这样:
// Inside switch:
case reflect.Chan:
e.WriteByte('[')
i := 0
for {
x, ok := v.Recv()
if !ok {
break
}
if i > 0 {
e.WriteByte(',')
}
e.reflectValue(x)
i++
}
e.WriteByte(']')
我对reflect
中的频道做的不多,所以上面的内容可能还需要其他检查。
如果你最终走这条路线,你总是可以提交补丁。
答案 1 :(得分:1)
您可以在结构中的MarshalJSON
方法中解压缩频道,如下所示:
type S struct {
Foo string
Bar chan string
}
func (s *S) MarshalJSON() (b []byte, err error) {
b, err := json.Marshal(s.Foo)
if err != nil { return nil, err }
for x := range s.Bar {
tmp, err := json.Marshal(x)
if err != nil { return nil, err }
b = append(b, tmp...)
}
return
}