如何在golang中用小内存读取大文件?
How to read huge files with samll ram in golang?
我有这样的文档,我想循环读取每个文件,大小为 5GB,我尝试了一些方法,例如 (file, err := ioutil.ReadFile(filename)) 但它加载了整个文件文件到 memory.I 使用此函数加载文件:
func visit(files *[]string) filepath.WalkFunc {
return func(path string, info os.FileInfo, err error) error {
if err != nil {
log.Fatal(err)
}
*files = append(*files, path)
return nil
}
}
对于我使用的读取文件:
file, err := os.Open("file")
if err != nil {
log.Fatal(err)
}
defer file.Close()
buf := make([]byte,10*1024)
for {
n, err := file.Read(buf)
if n > 0 {
fmt.Print(buf[:n])
}
if err == io.EOF {
break
}
我想解析buf中的数据
err = xml.Unmarshal(buf, &m)
if err != nil {
log.Fatal(err)
}
fmt.Println(m)
米是:
type M struct {
Mc []struct {
Id string `xml:"id"`
NeId string `xml:"neid"`}`xml:"mc"`
Mr struct {
Mh []string `xml:"mh"`}`xml:"mr"`
}
在 func main 中:
func main() {
var files []string
root := "/folder/files"
err := filepath.Walk(root, visit(&files))
if err != nil {
panic(err)
}
for _, file := range files {
但是执行的时间太长了,我该怎么做才能加快这个过程呢?
我在第 496 行收到错误 XML 语法错误:意外的 EOF。
并发在这种情况下可能有用吗?
以下是一些可重现的基准测试结果:
固态硬盘:
$ echo 3 | sudo tee /proc/sys/vm/drop_caches
3
$ go build readfile.go && time ./readfile
/home/peter/Downloads/ubuntu-mate-18.10-desktop-amd64.iso is 2103607296 bytes
real 0m2.839s
user 0m0.283s
sys 0m1.064s
$
硬盘:
$ echo 3 | sudo tee /proc/sys/vm/drop_caches
3
$ go build readfile.go && time ./readfile
/home/peter/Downloads/ubuntu-mate-18.10-desktop-amd64.iso is 2103607296 bytes
real 0m14.194s
user 0m0.627s
sys 0m2.880s
$
硬盘:
$ echo 3 | sudo tee /proc/sys/vm/drop_caches
3
$ go build readfile.go && time ./readfile
/home/peter/Downloads/ubuntu-mate-18.10-desktop-amd64.iso is 2103607296 bytes
real 0m16.627s
user 0m0.431s
sys 0m1.608s
$
package main
import (
"bufio"
"fmt"
"io"
"os"
)
func readFile(fName string) (int64, error) {
f, err := os.Open(fName)
if err != nil {
return 0, err
}
defer f.Close()
r := bufio.NewReader(f)
nr := int64(0)
buf := make([]byte, 0, 4*1024)
for {
n, err := r.Read(buf[:cap(buf)])
buf = buf[:n]
if n == 0 {
if err == nil {
continue
}
if err == io.EOF {
break
}
return nr, err
}
// Do something with buf
nr += int64(len(buf))
if err != nil && err != io.EOF {
return nr, err
}
}
return nr, nil
}
func main() {
fName := `/home/peter/Downloads/ubuntu-mate-18.10-desktop-amd64.iso`
if len(os.Args) > 1 {
fName = os.Args[1]
}
nr, err := readFile(fName)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
fmt.Printf("%s is %d bytes\n", fName, nr)
}
您的可重现基准测试结果是什么?
我有这样的文档,我想循环读取每个文件,大小为 5GB,我尝试了一些方法,例如 (file, err := ioutil.ReadFile(filename)) 但它加载了整个文件文件到 memory.I 使用此函数加载文件:
func visit(files *[]string) filepath.WalkFunc {
return func(path string, info os.FileInfo, err error) error {
if err != nil {
log.Fatal(err)
}
*files = append(*files, path)
return nil
}
}
对于我使用的读取文件:
file, err := os.Open("file")
if err != nil {
log.Fatal(err)
}
defer file.Close()
buf := make([]byte,10*1024)
for {
n, err := file.Read(buf)
if n > 0 {
fmt.Print(buf[:n])
}
if err == io.EOF {
break
}
我想解析buf中的数据
err = xml.Unmarshal(buf, &m)
if err != nil {
log.Fatal(err)
}
fmt.Println(m)
米是:
type M struct {
Mc []struct {
Id string `xml:"id"`
NeId string `xml:"neid"`}`xml:"mc"`
Mr struct {
Mh []string `xml:"mh"`}`xml:"mr"`
}
在 func main 中:
func main() {
var files []string
root := "/folder/files"
err := filepath.Walk(root, visit(&files))
if err != nil {
panic(err)
}
for _, file := range files {
但是执行的时间太长了,我该怎么做才能加快这个过程呢? 我在第 496 行收到错误 XML 语法错误:意外的 EOF。 并发在这种情况下可能有用吗?
以下是一些可重现的基准测试结果:
固态硬盘:
$ echo 3 | sudo tee /proc/sys/vm/drop_caches
3
$ go build readfile.go && time ./readfile
/home/peter/Downloads/ubuntu-mate-18.10-desktop-amd64.iso is 2103607296 bytes
real 0m2.839s
user 0m0.283s
sys 0m1.064s
$
硬盘:
$ echo 3 | sudo tee /proc/sys/vm/drop_caches
3
$ go build readfile.go && time ./readfile
/home/peter/Downloads/ubuntu-mate-18.10-desktop-amd64.iso is 2103607296 bytes
real 0m14.194s
user 0m0.627s
sys 0m2.880s
$
硬盘:
$ echo 3 | sudo tee /proc/sys/vm/drop_caches
3
$ go build readfile.go && time ./readfile
/home/peter/Downloads/ubuntu-mate-18.10-desktop-amd64.iso is 2103607296 bytes
real 0m16.627s
user 0m0.431s
sys 0m1.608s
$
package main
import (
"bufio"
"fmt"
"io"
"os"
)
func readFile(fName string) (int64, error) {
f, err := os.Open(fName)
if err != nil {
return 0, err
}
defer f.Close()
r := bufio.NewReader(f)
nr := int64(0)
buf := make([]byte, 0, 4*1024)
for {
n, err := r.Read(buf[:cap(buf)])
buf = buf[:n]
if n == 0 {
if err == nil {
continue
}
if err == io.EOF {
break
}
return nr, err
}
// Do something with buf
nr += int64(len(buf))
if err != nil && err != io.EOF {
return nr, err
}
}
return nr, nil
}
func main() {
fName := `/home/peter/Downloads/ubuntu-mate-18.10-desktop-amd64.iso`
if len(os.Args) > 1 {
fName = os.Args[1]
}
nr, err := readFile(fName)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
fmt.Printf("%s is %d bytes\n", fName, nr)
}
您的可重现基准测试结果是什么?