我是新手,所以对特定于语言的结构了解不多。
我的用例是首先将包含以换行符分隔的 JSON blob 的输入文件读入内存。从这个 JSON 源“数组”中,我想解码每个数组元素以在 golang 中处理它。预期的结构映射已经定义。
我通常喜欢一次读取所有行,因此 ioutil.ReadFile()
如 How can I read a whole file into a string variable in Golang? 中所述似乎是个不错的选择。而 json.Unmarshal
似乎以字节数组为源。但是,如果我使用 ReadFile(),则整个文件只有一个字节数组。我如何提取此字节数组的 slice ,以便跳过换行符字节(作为分隔符)并且每个 slice 都是那些 JSON blob 之一?我假设最好的技术是不进行或最小化数据类型转换的技术。由于简单的 hack 类似于将字节数组转换为字符串,将换行符分隔的字符串拆分为数组,然后将每个字符串数组元素转换回字节以传递给 json.Unmarshal。我更喜欢优化方法,但不确定如何处理 go 中的实现算法细节,可以在这里使用一些提示。
理想情况下,我希望预先完成预处理,这样我就不会在遍历 slice 等时处理文件中的 JSON 字节数组的内容。相反,我想预处理单字节数组从文件读入字节数组 slice 数组,删除所有换行字节,每个 slice 都是由换行符分隔的段。
最佳答案
使用bufio.Scanner一次读一行:
f, err := os.Open(fname)
if err != nil {
// handle error
}
s := bufio.NewScanner(f)
for s.Scan() {
var v ValueTypeToUnmarshalTo
if err := json.Unmarshal(s.Bytes(), &v); err != nil {
//handle error
}
// do something with v
}
if s.Err() != nil {
// handle scan error
}
或使用 ioutil.ReadFile 吞噬整个文件并 bytes.Split将文件分成几行:
p, err := ioutil.ReadFile(fname)
if err != nil {
// handle error
}
for _, line := range bytes.Split(p, []byte{'\n'}) {
var v ValueTypeToUnmarshalTo
if err := json.Unmarshal(line, &v); err != nil {
//handle error
}
// do something with v
}
或使用 json.Decoder内置流功能,可从文件中读取多个值:
f, err := os.Open(fname)
if err != nil {
// handle error
}
d := json.NewDecoder(f)
for {
var v ValueTypeToUnmarshalTo
if err := d.Decode(&v); err == io.EOF {
break // done decoding file
} else if err != nil {
// handle error
}
// do something with v
}
Run the code on the playground
ioutil.ReadFile 方法比其他方法使用更多的内存(文件中每个字节一个字节加上每行一个 slice header )。
因为解码器会忽略 JSON 值后面的空格,所以这三种方法都会处理\r\n 行终止符。
除了将 JSON 字节解码为 Go 值所固有的那些方法之外,这些方法中的任何一种都没有数据转换。
关于go - 将换行符分隔的 JSON blob 的整个文件读取到内存中,并在 golang 中使用最少的转换量解码每个 blob?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34388083/