我有一些我要解析的大型json文件,我想避免一次将所有数据加载到内存中。我喜欢一个函数/循环,它可以一次一个地返回每个角色。
我发现this example用于迭代字符串中的单词,而bufio包中的the ScanRunes函数看起来可能一次返回一个字符。我也有bufio的ReadRune
函数主要工作,但这感觉就像一个非常沉重的方法。
我比较了3种方法。所有人都使用循环来从bufio.Reader或bufio.Scanner中提取内容。
.ReadRune
上的bufio.Reader
在循环中读取符文。检查了.ReadRune
。bufio.Scanner
后,从.Split(bufio.ScanRunes)
读取字节。在每次迭代时调用.Scan
和.Bytes
,检查.Scan
是否需要调用错误。.Text
从bufio.Scanner
而不是字节读取文本。我没有用string([]runes)
加入一片符文,而是用strings.Join([]strings, "")
加入了一段字符串,以形成最后的文本blob。23 MB json文件上每次运行10次的时间是:
0.65 s
2.40 s
0.97 s
所以看起来ReadRune
毕竟不是太糟糕。它还会导致较小的详细调用,因为每个符文都是在1次操作(.ReadRune
)而不是2次(.Scan
和.Bytes
)中获取的。
答案 0 :(得分:5)
此代码从输入中读取符文。不需要强制转换,它就像迭代器一样:
package main
import (
"bufio"
"fmt"
"strings"
)
func main() {
in := `{"sample":"json string"}`
s := bufio.NewScanner(strings.NewReader(in))
s.Split(bufio.ScanRunes)
for s.Scan() {
fmt.Println(s.Text())
}
}
答案 1 :(得分:5)
只需在循环中逐一阅读每个符文...... See example
编辑:为后代添加代码,以防链接死亡:
package main
import (
"bufio"
"fmt"
"io"
"log"
"strings"
)
var text = `
The quick brown fox jumps over the lazy dog #1.
Быстрая коричневая лиса перепрыгнула через ленивую собаку.
`
func main() {
r := bufio.NewReader(strings.NewReader(text))
for {
if c, sz, err := r.ReadRune(); err != nil {
if err == io.EOF {
break
} else {
log.Fatal(err)
}
} else {
fmt.Printf("%q [%d]\n", string(c), sz)
}
}
}
答案 2 :(得分:1)
如果只是内存大小。在即将发布的版本中(很快),将会有json解码器的令牌样式增强功能: 你可以在这里看到它