json - 不要将不需要的 JSON 键值读入内存

标签 json go

我有一个包含单个字段的 JSON 文件,当加载到内存中时,该文件占用巨大 的空间。其他字段是合理的,但我尽量注意不要加载该特定字段,除非我绝对必须这样做。

{
    "Field1": "value1",
    "Field2": "value2",
    "Field3": "a very very long string that potentially takes a few GB of memory"
}

将该文件读入内存时,我想忽略 Field3(因为加载它可能会使我的应用程序崩溃)。这里有一些代码,我认为这样做是因为它使用 io 流,而不是将 []byte 类型传递给 Unmarshal 命令。

package main

import (
    "encoding/json"
    "os"
)

func main() {
    type MyStruct struct {
        Field1 string
        Field2 string
    }
    fi, err := os.Open("myJSONFile.json")
    if err != nil {
        os.Exit(2)
    }
    // create an instance and populate
    var mystruct MyStruct
    err = json.NewDecoder(fi).Decode(&mystruct)
    if err != nil {
        os.Exit(2)
    }
    // do some other stuff
}

问题是内置的 json.Decoder 类型在丢弃与 struct 的字段(正如之前在 StackOverflow 上指出的那样:link)。

有没有什么方法可以在不将整个 JSON 对象保存在内存中的情况下在 Go 中解码 JSON?

最佳答案

您可以编写一个自定义的 io.Reader 并将其提供给 json.Decoder,这将预读您的 json 文件并跳过该特定字段。

另一种选择是编写自己的解码器,更加复杂和困惑。

//edit 这似乎是一个有趣的练习,所以这里是:

type IgnoreField struct {
    io.Reader
    Field string
    buf   bytes.Buffer
}

func NewIgnoreField(r io.Reader, field string) *IgnoreField {
    return &IgnoreField{
        Reader: r,
        Field:  field,
    }
}
func (iF *IgnoreField) Read(p []byte) (n int, err error) {
    if n, err = iF.Reader.Read(p); err != nil {
        return
    }
    s := string(p)
    fl := `"` + iF.Field + `"`
    if i := strings.Index(s, fl); i != -1 {
        l := strings.LastIndex(s[0:i], ",")
        if l == -1 {
            l = i
        }
        iF.buf.WriteString(s[0:l])

        s = s[i+1+len(fl):]
        i = strings.Index(s, `"`)
        if i != -1 {
            s = s[i+1:]
        }
        for {
            i = strings.Index(s, `"`) //end quote
            if i != -1 {
                s = s[i+1:]
                fmt.Println("Skipped")
                break
            } else {
                if n, err = iF.Reader.Read(p); err != nil {
                    return
                }
                s = string(p)
            }
        }
        iF.buf.WriteString(s)
    }
    ln := iF.buf.Len()
    if ln >= len(p) {
        tmp := iF.buf.Bytes()
        iF.buf.Reset()
        copy(p, tmp[0:len(p)])
        iF.buf.Write(p[len(p):])
        ln = len(p)
    } else {
        copy(p, iF.buf.Bytes())
        iF.buf.Reset()
    }
    return ln, nil
}

func main() {
    type MyStruct struct {
        Field1 string
        Field2 string
    }
    fi, err := os.Open("myJSONFile.json")
    if err != nil {
         os.Exit(2)
    }
    // create an instance and populate
    var mystruct MyStruct
    err := json.NewDecoder(NewIgnoreField(fi, "Field3")).Decode(&mystruct)
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println(mystruct)
}

playground

关于json - 不要将不需要的 JSON 键值读入内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25002575/

相关文章:

python - OSError : [Errno 22] when I try to . read() 一个 json 文件

go - 在 Ubuntu 18.04 的 $ANDROID_HOME/ndk-bundle 和 $ANDROID_NDK_HOME 中都没有找到 Android NDK

go - 为什么这个 go 例程在关闭阻塞读取连接时随机无法退出?

Golang变量声明语法含义

go - 迭代时我在 slice 中范围变化的值

php - JSON 的正确 MIME 类型?

python - SimpleJSON 和 NumPy 数组

java - Gson - Json 列表到 Java List<Object>

html - 在 angularjs 中使用 ng-repeat 动态创建表

mongodb - 查询期间文档的MongoDB求和字段