我想从不同的文本或json或csv文件读取数据。我应该采用哪种方法?
我已经阅读了这些博客File read,read 2GB text file with small RAM,以了解不同的文件读取方法。
* 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较小的文件的最快方法。
答案 0 :(得分: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)
}
}