Heim >Backend-Entwicklung >Golang >Wie kann man große Streaming-JSON-Dateien in Go effizient dekodieren?
Wenn Sie mit großen JSON-Antworten arbeiten, ist es nicht ideal, die gesamte Antwort vor der Dekodierung in den Speicher zu laden. Die Verwendung der Funktion ioutil.ReadAll kann bei der Verarbeitung großer JSON-Nutzlasten zu Speicherproblemen führen. In diesem Artikel erfahren Sie, wie Sie JSON-Daten während des Streams im Handumdrehen dekodieren und so Speicherverbrauchsprobleme vermeiden können.
Der json.Decoder in der Go-Standardbibliothek bietet die Möglichkeit, JSON-Streams inkrementell zu analysieren. Dies wird durch die Decoder.Token()-Methode erreicht.
Die Decoder.Token()-Methode gibt das nächste Token im JSON-Stream zurück, ohne es zu verbrauchen. Dies ermöglicht ein selektives Parsen von JSON-Daten und eine ereignisgesteuerte Verarbeitung.
Für das ereignisgesteuerte Parsen ist eine Zustandsmaschine erforderlich, um die aktuelle Position innerhalb der JSON-Struktur zu verfolgen. Wir können diese Zustandsmaschine verwenden, um verschiedene Teile der JSON-Daten so zu verarbeiten, wie sie im Stream erscheinen.
Nehmen wir zum Beispiel an, wir erhalten eine JSON-Antwort mit dem folgenden Format:
{ "property1": "value1", "property2": "value2", "array": [ { "item1": "value3" }, { "item2": "value4" } ] }
Wir können eine Funktion schreiben, die diesen JSON-Stream inkrementell analysiert und das Array-Element separat verarbeitet:
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" } } }
Bei Aufruf mit der JSON-Antwort wird diese Funktion ausgeführt Geben Sie die Eigenschaftsnamen und -werte sowie die einzelnen Elemente innerhalb des Arrays aus.
Die Verwendung von json.Decoder und Decoder.Token() in der ereignisgesteuerten Verarbeitung ermöglicht uns das Parsen große JSON-Antworten inkrementell, um Probleme mit dem Speicherverbrauch zu vermeiden und eine effiziente Verarbeitung der Daten beim Einströmen zu ermöglichen.
Das obige ist der detaillierte Inhalt vonWie kann man große Streaming-JSON-Dateien in Go effizient dekodieren?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!