【问题标题】:Multi line buffered read in go多行缓冲读取
【发布时间】:2019-11-27 16:21:15
【问题描述】:

我正在尝试以缓冲方式读取文件,因为我有非常大的文件。我想对文件应用一些文本替换。假设每次阅读我都搜索一个单词“foo”并将其替换为其他单词“bar”。如果我使用某个大小为 5MB 的缓冲区进行读取,那么 foo 可能会分成两次读取,可能一次读取 'fo',另一次读取 'o',那么我将无法找到该单词。有没有办法让我可以使用缓冲读取到最后一个换行符,或者可以在缓冲区中读取多行 我在下面做了。但它不会读到下一行或上一行

file, err := os.Open(filename)
if err != nil {
    panic(err)
}
defer file.Close()

byteSlice := make([]byte, 5*1024*1024) // read 5 MB
bufioreader := bufio.NewReaderSize(file, bufferSize)

for {
    n, err := bufioreader.Read(byteSlice)
    if n > 0 {
        fmt.Println(byteSlice[:n])
    } else if err == io.EOF {
        break
    } else {
        panic(err)
    }
}

【问题讨论】:

    标签: go


    【解决方案1】:

    由于您使用的是 bufio 阅读器,因此您不应该真正自己将输入与缓冲区边界对齐。使用高级读取函数之一,例如 `bufioreader.ReadString('\n'),它将使用底层缓冲区读取一行,您不必自己处理行分隔符。

    【讨论】:

    • 在我的文件中,行很小可能是 50 个字符,但文件大小可能是 500 MB 到 500 GB。因此,如果我逐行读取,它将被大量读取(例如系统调用的数十亿读取开销)。这就是为什么我想根据我的 RAM 使用 5MB 或 500 MB 的缓冲区大小
    • 如果使用较大的缓冲区大小,每次读取都会填满缓冲区,然后阅读器会解析该缓冲区中的行。它不会为每一行重新读取文件。
    【解决方案2】:

    如果您有自己的缓冲区,则不需要 bufio 阅读器。使用您的代码,您可以将数据从 bufio 中的缓冲区复制到字节片。

    关于拆分“foo”问题,解决方案是在下一次读取之前将缓冲区的最后 2 个字符移到前面。

    更准确地说,如果要替换的单词长度为m,则将缓冲区的最后一个m-1个字母复制到缓冲区的前面,填充剩余的缓冲区并在缓冲区中搜索要替换的单词。

    // assume we want to find word
    
    file, err := os.Open(filename)
    if err != nil {
        panic(err)
    }
    defer file.Close()
    
    trailingLen := len(word)-1
    dataLen := 5*1024*1024 + trailingLen
    data := make([]byte, dataLen) // read 5 MB
    
    for {
        n, err := file.Read(data[trailingLen:])
        if err != nil {
            if err == io.EOF {
                break
            }
            panic(err)
        }
        // search and replace word in data[:n]
    
        if n == dataLen {
            copy(data, data[dataLen-trailingLen:])
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多