首页 >后端开发 >Golang >如何在不将整个负载加载到内存中的情况下高效解码 JSON 流?

如何在不将整个负载加载到内存中的情况下高效解码 JSON 流?

Barbara Streisand
Barbara Streisand原创
2024-12-25 18:44:14941浏览

How to Efficiently Decode JSON Streams without Loading the Entire Payload into Memory?

在不读取整个有效负载的情况下解码 JSON 流

在这种情况下,我们需要解码通过 HTTP 流接收的 JSON 数据而不加载整个反应进入记忆。目标是处理单个 JSON 项(在数组中表示为“大对象”),并在收到它们时将它们分派到消息队列。

事件驱动的 JSON 解析

为了实现这一点,我们使用 json.Decoder 及其 Decode() 和 Token() 方法。 Decode() 可用于解组单个值,而 Token() 允许我们仅解析 JSON 流中的下一个标记,使我们能够增量处理数据。

On-the- Fly 令牌处理

我们建立一个“状态机”来跟踪我们在 JSON 结构中的位置。通过分析每个标记,我们浏览对象层次结构,识别“items”数组及其大对象元素。

代码实现

package main

import (
    "bufio"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "os"
)

// Helper error handler
func he(err error) {
    if err != nil {
        log.Fatal(err)
    }
}

// Large object struct
type LargeObject struct {
    Id   string `json:"id"`
    Data string `json:"data"`
}

func main() {
    // JSON input for demonstration
    in := `{"somefield": "value", "otherfield": "othervalue", "items": [ {"id": "1", "data": "data1"}, {"id": "2", "data": "data2"}, {"id": "3", "data": "data3"}, {"id": "4", "data": "data4"}]}`

    dec := json.NewDecoder(strings.NewReader(in))

    // Expect an object
    t, err := dec.Token()
    he(err)
    if delim, ok := t.(json.Delim); !ok || delim != '{' {
        log.Fatal("Expected object")
    }

    // Read props
    for dec.More() {
        t, err = dec.Token()
        he(err)
        prop := t.(string)
        if t != "items" {
            var v interface{}
            he(dec.Decode(&v))
            fmt.Printf("Property '%s' = %v\n", prop, v)
            continue
        }

        // It's the "items". Expect an array
        t, err = dec.Token()
        he(err)
        if delim, ok := t.(json.Delim); !ok || delim != '[' {
            log.Fatal("Expected array")
        }
        // Read items (large objects)
        for dec.More() {
            // Read next item (large object)
            lo := LargeObject{}
            he(dec.Decode(&lo))
            fmt.Printf("Item: %+v\n", lo)
        }
        // Array closing delim
        t, err = dec.Token()
        he(err)
        if delim, ok := t.(json.Delim); !ok || delim != ']' {
            log.Fatal("Expected array closing")
        }
    }

    // Object closing delim
    t, err = dec.Token()
    he(err)
    if delim, ok := t.(json.Delim); !ok || delim != '}' {
        log.Fatal("Expected object closing")
    }
}

示例输出

Property 'somefield' = value
Property 'otherfield' = othervalue
Item: {Id:1 Data:data1}
Item: {Id:2 Data:data2}
Item: {Id:3 Data:data3}
Item: {Id:4 Data:data4}

通过使用这种事件驱动的解析方法,我们可以有效地处理大的 JSON 增量响应,避免过多的内存消耗。

以上是如何在不将整个负载加载到内存中的情况下高效解码 JSON 流?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn