首頁 >後端開發 >Golang >如何在 Go 中高效解碼大型串流 JSON?

如何在 Go 中高效解碼大型串流 JSON?

Mary-Kate Olsen
Mary-Kate Olsen原創
2025-01-02 20:03:40368瀏覽

How to Efficiently Decode Large Streaming JSON in Go?

如何在 Go 中解碼串流 JSON

處理大型 JSON 回應時,在解碼之前將整個回應載入記憶體並不理想。處理大型 JSON 有效負載時,使用 ioutil.ReadAll 函數可能會導致記憶體問題。本文將探討如何在 JSON 資料流入時進行動態解碼,避免記憶體消耗問題。

使用 json.Decoder 進行 JSON 流

Go 標準庫中的 json.Decoder 提供了增量解析 JSON 流的能力。這是透過 Decoder.Token() 方法實現的。

Decoder.Token() 方法傳回 JSON 流中的下一個令牌,而不消耗它。這允許選擇性解析 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中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn