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

tur*_*nvh 5 io parsing json go

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

我发现这个例子用于迭代字符串中的单词,而bufio包中的ScanRunes函数看起来可能一次返回一个字符.我也有ReadRunebufio 的功能主要工作,但这感觉像一个非常沉重的方法.

编辑

我比较了3种方法.所有都使用循环来从bufio.Reader或bufio.Scanner中提取内容.

  1. 使用.ReadRunea 在循环中读取符文bufio.Reader.检查来电的错误.ReadRune.
  2. bufio.Scanner在调用.Split(bufio.ScanRunes)扫描仪之后从a读取字节.调用.Scan.Bytes在每次迭代时检查.Scan调用错误.
  3. 与#2相同,但bufio.Scanner使用的是从a 而不是字节读取文本.Text.string([]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)中获取的.

小智 7

只需在循环中逐个阅读每个符文...... 参见示例

编辑:为后代添加代码,以防链接死亡:

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)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Ale*_*hov 6

此代码从输入中读取符文.不需要强制转换,它是迭代器:

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())
    }
}
Run Code Online (Sandbox Code Playgroud)