Golang读取文件和处理超大文件方案
方法一、文件整体读取
文件整体读取就是将文件一次性读取到,理解上是将文件的内容第一次就读取完了
使用场景 :
- 针对小文件比较合适(大文件读取空间和时间的消耗也很大)
- 对于整体性强的文件也比较合适(文件也不能太大)
示例代码:
package main
import (
"bufio"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"time"
)
// 测试用的文本文件11M大小
var m11 string = `G:\runtime\log\ccapi\11M.log`
// 测试用的文本文件400M大小
var m400 string = `G:\runtime\log\ccapi\400M.log`
// 将整个文件都读取
func readAll(filePath string) {
start1 := time.Now()
ioutil.ReadFile(filePath)
fmt.Println("readAll spend : ", time.Now().Sub(start1))
}
func main() {
readAll(m11)
readAll(m400)
}
方法二:文件分片读取
对文件一部分一部分逐步的读取,直到文件完全读取完。
每次读取文件的大小是根据设置的 分片 大小 ,所以对于读取文本类型的文件时(例如 : 日志文件)
不一定是按照你的期望逐行输出,因为不会处理文本尾部的换行符,而是按照分片大小读取内容
使用场景 :
1、读取超大的文件很合适
2、读二进制类型的文件很合适(比如:音视频文件或者资源类型文件等)
示例代码:
package main
import (
"bufio"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"time"
)
// 测试用的文本文件11M大小
var m11 string = `G:\runtime\log\ccapi\11M.log`
// 测试用的文本文件400M大小
var m400 string = `G:\runtime\log\ccapi\400M.log`
// 文件一块一块的读取
func readBlock(filePath string) {
start1 := time.Now()
FileHandle, err := os.Open(filePath)
if err != nil {
log.Println(err)
return
}
defer FileHandle.Close()
// 设置每次读取字节数
buffer := make([]byte, 1024)
for {
n, err := FileHandle.Read(buffer)
// 控制条件,根据实际调整
if err != nil && err != io.EOF {
log.Println(err)
}
if n == 0 {
break
}
// 如下代码打印出每次读取的文件块(字节数)
//fmt.Println(string(buffer[:n]))
}
fmt.Println("readBolck spend : ", time.Now().Sub(start1))
}
func main() {
readBlock(m11)
readBlock(m400)
}
方法三:文件逐行读取
对文件一行一行的读取,直到读到文件末尾
使用场景 :
- 读取超大的文件很合适(例如 : 超大log文件等)
- 读取的文件最好是有换行的(如果使用单行文件组成的大文件,需要注意)
- 对需要分析内容的大文件
- 统计某些数据出现的次数
- 查询某些数据是否存在
- 查找指定行的数据
示例代码:
package main
import (
"bufio"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"time"
)
// 测试用的文本文件11M大小
var m11 string = `G:\runtime\log\ccapi\11M.log`
// 测试用的文本文件400M大小
var m400 string = `G:\runtime\log\ccapi\400M.log`
// 读取文件的每一行
func readEachLineReader(filePath string) {
start1 := time.Now()
FileHandle, err := os.Open(filePath)
if err != nil {
log.Println(err)
return
}
defer FileHandle.Close()
lineReader := bufio.NewReader(FileHandle)
for {
// 相同使用场景下可以采用的方法
// func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error)
// func (b *Reader) ReadBytes(delim byte) (line []byte, err error)
// func (b *Reader) ReadString(delim byte) (line string, err error)
line, _, err := lineReader.ReadLine()
if err == io.EOF {
break
}
// 如下是某些业务逻辑操作
// 如下代码打印每次读取的文件行内容
fmt.Println(string(line))
}
fmt.Println("readEachLineReader spend : ", time.Now().Sub(start1))
}
func main(){
readEachLineReader(m11)
readEachLineReader(m400)
}