Go语言中常用的几种文件读写的方法分别为os.Open、bufio和ioutil。下面比较的直接调用File对象的Read函数、bufio的NewReader函数和ioutil的ReadAll的性能
package main
import (
"fmt"
"time"
"os"
"bufio"
"io/ioutil"
)
// os.Open
func read1(filepath string) string {
f, err := os.Open(filepath)
if err != nil{
panic(err)
}
defer f.Close()
chunks := make([]byte,1024,1024)
buf := make([]byte,1024)
for {
n, err := f.Read(buf)
if err != nil || 0 == n {
break
}
chunks = append(chunks, buf[:n]...)
}
return string(chunks)
}
// bufio
func read2(filepath string) string {
file, err := os.Open(filepath)
if err != nil{
panic(err)
}
defer file.Close()
chunks := make([]byte,1024,1024)
f := bufio.NewReader(file)
buf := make([]byte,1024)
for {
n, err := f.Read(buf)
if err != nil || 0 == n {
break
}
chunks = append(chunks, buf[:n]...)
}
return string(chunks)
}
// ioutil
func read3(filepath string) string {
file, err := os.Open(filepath)
if err != nil{
panic(err)
}
defer file.Close()
f, _ := ioutil.ReadAll(file)
txt := string(f)
return txt
}
func main() {
filepath := "somefile.txt"
t1 := time.Now()
read1(filepath)
elapsed1 := time.Since(t1)
fmt.Println("cost ", elapsed1)
t2 := time.Now()
read2(filepath)
elapsed2 := time.Since(t2)
fmt.Println("cost ", elapsed2)
t3 := time.Now()
read3(filepath)
elapsed3 := time.Since(t3)
fmt.Println("cost ", elapsed3)
}
文件大小为48.47M,结果为
cost 222.050377ms
cost 111.779435ms
cost 82.178851ms
具体的性能差异,涉及到源码层面了。应该和源码中使用的buffer和系统调用中使用的buffer有关(是不是这两处的buffer还不一样呢,有空研究一下)。理论上说,系统调用读文件读的缓存区越大,调用次数越少,耗时越少。参考https://segmentfault.com/a/1190000011680507
使用时,根据需求选择:如果需要一次性读取,用ioutil.ReadFile和ioutil.ReadAll方便;如果需要分块或分行,用bufio的Read、ReadString或者ReadLine更加方便;如果是大文件读写的话,用bufio。