file - 使用小 RAM 在 Go 中读取大文件的最快方法

标签 file go

<分区>

我想从不同的文本或JSON中读取数据或 CSV文件。我应该遵循哪种方法?

我有博文File readRead 2 GB text file with small RAM用于文件读取的不同方法。

不同的方法:

  • 分块读取文件
  • 同时读取文件 block
  • 将整个文件读入内存
  • 将长字符串拆分为单词
  • 逐字扫描

用小 RAM 读取文件的最快方法是什么?

最佳答案

基本上有两种不同的方法来解析文件:文档解析和流解析。

文档解析从文件中读取数据并将其转换为一大组您可以查询的对象,例如 HTML DOM在浏览器中。优点是您可以轻松获得完整的数据,这通常更简单。缺点是您必须将其全部存储在内存中。

dom = parse(stuff)

// Now do whatever you like with the DOM

流式解析改为一次读取一个元素并将其呈现给您以供立即使用,然后继续进行下一个元素。

for element := range stream(stuff) {
    ...examine one element at a time...
}

优点是您不必将整个内容加载到内存中。缺点是您必须在数据经过时对其进行处理。这对于搜索或任何其他需要逐一处理的事情非常有用。


幸运的是,Go 提供了库来为您处理常见格式。

一个简单的例子是处理 CSV 文件。

package main

import(
    "encoding/csv"
    "fmt"
    "log"
    "os"
    "io"
)

func main() {
    file, err := os.Open("test.csv")
    if err != nil {
        log.Fatal(err)
    }

    parser := csv.NewReader(file)

    ...
}

我们可以将整个内容作为一个大的[][]string 放入内存。

records, err := parser.ReadAll()
if err != nil {
    log.Fatal(err)
}

for _,record := range records {
    fmt.Println(record)
}

或者我们可以节省大量内存并一次处理一行。

for {
    record, err := parser.Read()
    if err == io.EOF {
        break
    }
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(record)
}

由于 CSV 的每一行在功能上都是相同的,因此一次处理一行最有意义。

JSON 和 XML 更为复杂,因为它们是大型嵌套结构,但它们也可以流式传输。有 an example of streaming in the encoding/json documentation .


如果您的代码不是一个简单的循环怎么办?如果你想利用并发怎么办?使用一个 channel 和一个 goroutine 与程序的其余部分同时提供它。

records := make( chan []string )
go func() {
    parser := csv.NewReader(file)

    defer close(records)
    for {
        record, err := parser.Read()
        if err == io.EOF {
            break
        }
        if err != nil {
            log.Fatal(err)
        }

        records <- record
    }
}();

现在您可以将记录传递给可以处理它们的函数。

func print_records( records chan []string ) {
    for record := range records {
        fmt.Println(record)
    }
}

关于file - 使用小 RAM 在 Go 中读取大文件的最快方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52154609/

相关文章:

python - 在 Python 中将数据写入磁盘作为后台进程

javascript - 以文件作为参数的 React Api 调用

c++ - 来自文件的着色器,程序停止工作

c++ - 如何痛饮省略前向声明

git - 如何设置 GoReleaser 将 brew tap 推送到不同的存储库

c++ - 二进制文件大小大于预期的 C++

c - 从 txt 文件 C 中读取和比较数字

go - 为什么标准库bufio.Read(p [] byte)(int,err)在Go中检查len(p)而不是cap(p)

go - 如何为当前操作系统构建go包并将其输出到指定文件夹?

multithreading - 戈朗 : how to bind code with thread?