用小RAM读取大文件的最快方法[关闭]

问题描述 投票:-4回答:1

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

我已经阅读了这些博客File readread 2GB text file with small RAM,了解不同的文件阅读方法。

Different approach:

* Reading a file in chunks
* Reading file chunks concurrently
* Reading the entire file into memory
* Splitting a long string into words
* Scanning word by word

无法找到使用小RAM读取文件的最快方法。

file go
1个回答
2
投票

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

文档解析从文件中读取数据并将其转换为可以查询的大量对象,例如浏览器中的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


如果您的代码不是简单的循环怎么办?如果你想利用并发性怎么办?使用通道和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
    }
}();

现在你可以将records传递给一个可以处理它们的函数。

func print_records( records chan []string ) {
    for record := range records {
        fmt.Println(record)
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.