Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Go中读取JSON对象而不进行解码(用于读取大数据流)_Json_Go_Stream_Decode_Unmarshalling - Fatal编程技术网

如何在Go中读取JSON对象而不进行解码(用于读取大数据流)

如何在Go中读取JSON对象而不进行解码(用于读取大数据流),json,go,stream,decode,unmarshalling,Json,Go,Stream,Decode,Unmarshalling,我正在读取JSON以响应HTTP端点,并希望提取嵌套在其中的对象数组的内容。响应可能很大,所以我尝试使用流式方法,而不仅仅是json。JSON看起来是这样的: { "useless_thing_1": { /* etc */ }, "useless_thing_2": { /* etc */ }, "the_things_i_want": [ { /* complex object I want to json.Unmarshal #1 */ }, { /* complex object

我正在读取JSON以响应HTTP端点,并希望提取嵌套在其中的对象数组的内容。响应可能很大,所以我尝试使用流式方法,而不仅仅是json。JSON看起来是这样的:

{
"useless_thing_1": { /* etc */ },
"useless_thing_2": { /* etc */ },
"the_things_i_want": [
  { /* complex object I want to json.Unmarshal #1 */ },
  { /* complex object I want to json.Unmarshal #2 */ },
  { /* complex object I want to json.Unmarshal #3 */ },
  /* could be many thousands of these */
],
"useless_thing_3": { /* etc */ },
}
Go提供的json库具有json.Unmarshal,它适用于完整的json对象。它还具有json.Decoder,可以解组完整对象或提供单个标记。我可以使用这个标记器仔细检查并提取内容,但这样做的逻辑有点复杂,在我将其作为标记读取之后,我无法轻松地在对象上使用json.Unmarshal

json.Decoder是缓冲的,这使得读取一个对象(即{/*我想要json.Unmarshal 1*/}的复杂对象,然后使用,我自己,并创建一个新的json.Decoder)变得很困难,因为它将尝试使用逗号本身。这是我尝试过的方法,但没有成功

我正在寻找解决这个问题的更好办法。下面是我试图手动使用逗号时出现的错误代码:

//这里的代码天真地寻找“我想要的东西:[”和 //将其后面的下一个字节放入'buffer'中` //这是从`{/*复杂对象开始的流的其余部分,我想要json.Unmarshal 1*/}` in:=io.MultiReaderbuffer,res.Body dec:=json.NewDecoderin 为了{ var p MyComplexThing 错误:=dec.Decode&p 如果错误!=零{ 圆锥花序 } //直接从中窃取逗号-这不起作用,因为解码器缓冲区是它的输入 变量b1[1]字节 _,err=io.readAtlastin,b1[:],1//返回流中后面部分的随机数据 如果错误!=零{ 圆锥花序 } 开关b1[0]{ 案例',': //跳过它 案例']': 休息//我们结束了 违约: 从读取%v,b1得到的预期结果 } } 使用和将JSON文档解码为流

浏览文档,了解感兴趣的JSON值。调用unmarshal将JSON值转换为Go值。根据需要重复上述步骤,以清除所有感兴趣的值

下面是一些带有注释的代码,解释了它的工作原理:

func decode(r io.Reader) error {
    d := json.NewDecoder(r)

    // We expect that the JSON document is an object.
    if err := expect(d, json.Delim('{')); err != nil {
        return err
    }

    // While there are fields in the object...
    for d.More() {

        // Get field name
        t, err := d.Token()
        if err != nil {
            return err
        }

        // Skip value if not the field that we are looking for.
        if t != "the_things_i_want" {
            if err := skip(d); err != nil {
                return err
            }
            continue
        }

        // We expect JSON array value for the field.
        if err := expect(d, json.Delim('[')); err != nil {
            return err
        }

        // While there are more JSON array elements...
        for d.More() {

            // Unmarshal and process the array element.

            var m map[string]interface{}
            if err := d.Decode(&m); err != nil {
                return err
            }
            fmt.Printf("found %v\n", m)
        }

        // We are done decoding the array.
        return nil

    }
    return errors.New("things I want not found")
}

// skip skips the next value in the JSON document.
func skip(d *json.Decoder) error {
    n := 0
    for {
        t, err := d.Token()
        if err != nil {
            return err
        }
        switch t {
        case json.Delim('['), json.Delim('{'):
            n++
        case json.Delim(']'), json.Delim('}'):
            n--
        }
        if n == 0 {
            return nil
        }
    }
}

// expect returns an error if the next token in the document is not expectedT.
func expect(d *json.Decoder, expectedT interface{}) error {
    t, err := d.Token()
    if err != nil {
        return err
    }
    if t != expectedT {
        return fmt.Errorf("got token %v, want token %v", t, expectedT)
    }
    return nil
}

.

用于浏览文档到感兴趣的点。调用unmarshal将JSON值转换为Go值。根据需要重复此操作以清除所有感兴趣的值。有关跳过任意JSON值的函数,请参阅。将一个简单的JSON.Unmarshal转换为一个结构变量,该结构变量只声明一个字段作为“我想要的东西”,应该也能起作用:它当然会读取所有无用的东西并对其进行词法分析。您也必须这样做,但不能对其进行解组。@Volker是的,我明白,但这意味着我必须对数据进行处理,直到所有数据都被解封,最好是流式处理。这里有三件事:1。你必须阅读你想要处理的东西,任何技术都不能让你省掉这些。2.您必须至少在感兴趣的部分结束之前解码JSON,同样,没有任何技术可以为您提供此功能。3.你必须至少解开你感兴趣的部分,没有任何技术可以让你做到这一点。