大規模な JSON 応答を処理する場合、デコードする前に応答全体をメモリにロードするのは理想的ではありません。 ioutil.ReadAll 関数を使用すると、大きな JSON ペイロードを処理するときにメモリの問題が発生する可能性があります。この記事では、メモリ消費の問題を回避しながら、JSON データをストリーミング中にオンザフライでデコードする方法について説明します。
Go 標準ライブラリの json.Decoder は、次のことを提供します。 JSON ストリームを段階的に解析する機能。これは、Decoder.Token() メソッドによって実現されます。
Decoder.Token() メソッドは、JSON ストリーム内の次のトークンを消費せずに返します。これにより、JSON データの選択的な解析とイベント駆動型の処理が可能になります。
イベント駆動型の解析では、JSON 構造内の現在の位置を追跡するステート マシンが必要です。このステート マシンを使用して、ストリームに表示される JSON データのさまざまな部分を処理できます。
たとえば、次の形式の JSON 応答を受信したとします:
{ "property1": "value1", "property2": "value2", "array": [ { "item1": "value3" }, { "item2": "value4" } ] }
この JSON ストリームを段階的に解析し、配列要素を個別に処理する関数を作成できます。
func processJSONStream(stream io.Reader) { decoder := json.NewDecoder(stream) state := "start" for decoder.More() { token, err := decoder.Token() if err != nil { log.Fatal(err) } switch state { case "start": if delim, ok := token.(json.Delim); ok && delim == '{' { state = "object" } else { log.Fatal("Expected object") } case "object": switch t := token.(type) { case json.Delim: if t == '}' { // End of object state = "end" } else if t == ',' { // Next property continue } else if t == '[' { // Array found state = "array" } if t == ':' { // Property value expected state = "prop_value" } case string: // Property name fmt.Printf("Property '%s'\n", t) default: // Property value fmt.Printf("Value: %v\n", t) } case "array": if delim, ok := token.(json.Delim); ok && delim == ']' { // End of array state = "object" } else if token == json.Delim('{') { // Array item object fmt.Printf("Item:\n") state = "item" } case "item": switch t := token.(type) { case json.Delim: if t == '}' { // End of item object fmt.Printf("\n") state = "array" } else if t == ',' { // Next item property fmt.Printf(",\n") continue } case string: // Item property name fmt.Printf("\t'%s'", t) default: // Item property value fmt.Printf(": %v", t) } case "prop_value": // Decode the property value var value interface{} if err := decoder.Decode(&value); err != nil { log.Fatal(err) } fmt.Printf("Value: %v\n", value) state = "object" } } }
JSON 応答で呼び出された場合、この関数は、プロパティ名と値、配列内の個々の項目を出力します。
イベント駆動型処理で json.Decoder と Decoder.Token() を使用すると、次のことが可能になります。大規模な JSON 応答を段階的に解析し、メモリ消費の問題を回避し、データがストリーミングされる際の効率的な処理を可能にします。
以上がGo で大規模なストリーミング JSON を効率的にデコードするにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。