我想用来json.Encoder编码大量数据,而不必一次将所有数据加载到内存中。
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 }
不幸的是,该encoding/json程序包还没有办法做到这一点。您现在(手动)执行的操作是执行此操作的最佳方法,而无需修改内置程序包。
encoding/json
如果要打补丁encoding/json,则可以reflectValueQuoted在encoding / json / encode.go中修改功能
reflectValueQuoted
您可能需要关注Array的情况(Slice有一个fallthrough):
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,因此上述内容可能需要其他检查。
reflect
如果您确实选择了此方法,则可以随时提交补丁。