一尘不染

如何在Go中逐个字符读取文件

go

我有一些要解析的大型json文件,我想避免一次将所有数据加载到内存中。我想要一个可以一次返回每个字符的函数/循环。

我发现这个示例可以遍历字符串中的单词,而bufio包中的ScanRunes函数似乎可以一次返回一个字符。我也有ReadRunebufio提供的功能,大多数情况下都可以正常工作,但是感觉很沉重。

编辑

我比较了3种方法。全部使用循环从bufio.Reader或bufio.Scanner中提取内容。

  1. 阅读符文使用循环.ReadRunebufio.Reader。检查了从到的调用是否出错.ReadRune
  2. bufio.Scanner调用.Split(bufio.ScanRunes)扫描仪后,从中读取字节。在每次迭代中调用,.Scan.Bytes检查.Scan调用是否存在错误。
  3. 与#2相同,但bufio.Scanner使用而不是字节从a读取文本.Textstring([]runes)我没有使用strings.Join([]strings, "")来连接一小段符文,而是使用来连接一小段字符串来形成文本的最终斑点。

在23 MB的json文件上运行10次的时间是:

  1. 0.65 s
  2. 2.40 s
  3. 0.97 s

所以看起来ReadRune毕竟还算不错。由于每个符文都以1个操作(.ReadRune)而不是2(.Scan.Bytes)提取,因此它也导致较小的详细调用。


阅读 310

收藏
2020-07-02

共1个答案

一尘不染

只需在循环中逐一读取每个符文… 参见示例

编辑 :为后代添加代码,以防链接消失:

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)
        }
    }
}
2020-07-02