问题
比如我们有一个log文件,运行了几年,有100G之大。按照我们之前的操作可能代码会这样写:
1
2
3
4
5
6
7
|
func ReadFile(filePath string) []byte{
content, err := ioutil.ReadFile(filePath)
if err != nil {
log.Println("Read error")
}
return content
}
|
上面的代码读取几兆的文件可以,但是如果大于你本身及其内存,那就直接翻车了。因为上面的代码,是把文件所有的内容全部都读取到内存之后返回,几兆的文件,你内存够大可以处理,但是一旦上几百兆的文件,就没那么好处理了.
按行读取
逐行读取文件有两个函数,分别为bufio包中的 ReadString 和 ReadLine 函数
ReadString
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
func ReadString(filename string) error {
f, _ := os.Open(filename)
defer f.Close()
r := bufio.NewReader(f)
for {
line, err := r.ReadString('\n')
if err != nil {
if err == io.EOF{
fmt.Println(line)//注意如果遇到了io.EOF,line中保存了遇到了EOF之前的数据,可以直接输出
return nil
}
return err
}
fmt.Println(line)
}
}
|
ReadLine
ReadLine尝试返回一行数据,不包括行尾标志的字节。如果行太长超过了缓冲,返回值isPrefix会被设为true,并返回行的前面一部分。该行剩下的部分将在之后的调用中返回。返回值isPrefix会在返回该行最后一个片段时才设为false。返回切片是缓冲的子切片,只在下一次读取操作之前有效。ReadLine要么返回一个非nil的line,要么返回一个非nil的err,两个返回值至少一个非nil。默认缓冲为4096
ReadLine 读取文件更快,原因是由于 ReadString 后端调用 ReadBytes,而 ReadBytes 多次使用 copy 方法造成大量耗时。
1
2
3
4
5
6
7
8
9
10
11
|
func ReadLine(filename string) {
f, _ := os.Open(filename)
defer f.Close()
r := bufio.NewReader(f)
for {
_, err := readLine(r)
if err != nil {
break
}
}
}
|
此函数主要解决单行字节数大于4096的情况
1
2
3
4
5
6
7
8
9
|
func readLine(r *bufio.Reader) (string, error) {
line, isprefix, err := r.ReadLine()
for isprefix && err == nil {
var bs []byte
bs, isprefix, err = r.ReadLine()
line = append(line, bs...)
}
return string(line), err
}
|
分片读取
第二个方案就是分片处理,当读取的是二进制文件,没有换行符的时候,使用下面的方案一样处理大文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
func ReadBigFile(fileName string, handle func([]byte)) error {
f, err := os.Open(fileName)
if err != nil {
fmt.Println("can't opened this file")
return err
}
defer f.Close()
s := make([]byte, 4096)
for {
switch nr, err := f.Read(s[:]); true {
case nr < 0:
fmt.Fprintf(os.Stderr, "cat: error reading: %s\n", err.Error())
os.Exit(1)
case nr == 0: // EOF
return nil
case nr > 0:
handle(s[0:nr])
}
}
return nil
}
|
转载
http://www.voidcn.com/article/p-dzsrqswp-bnv.html
https://golangcaff.com/articles/110/two-schemes-for-reading-golang-super-large-files?order_by=vote_count&