【问题】最近想在一个10G的文件上读取最后100行数据,用了多种方式去实现,发现还是逆向读取比较香一点
【方法】分别尝试了两种方式:双端队列和逆读文件
在这里我就直接把结论放在文章前面
- 双端队列:适用于文件数据不大的情况,效率会达到最高
- 逆读文件:适用于大文件,会有不俗的读取速率,内存占用也不高
开始前,先亮一下【读取文件正常操作】
path := "/www/" + siteName + ".log"
num := 100
data := make([]string, 0, num)
file, err := os.Open(path)
if err != nil {
return data
}
defer file.Close()
// 顺读日志信息
scanner := bufio.NewScanner(file)
for scanner.Scan() && len(data) < num {
data = append(data, scanner.Text())
}
if err := scanner.Err(); err != nil {
fmt.Fprintln(os.Stderr, "reading standard input:", err)
}
return data
一、双端队列实现读取100行数据
data1 := list.New()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
// 将新的行添加到队列的末尾
data1.PushBack(scanner.Text())
// 如果队列的大小超过100,从队列的头部移除元素
if data1.Len() > num {
e := data1.Front()
data1.Remove(e)
}
}
if err := scanner.Err(); err != nil {
fmt.Fprintln(os.Stderr, "reading standard input:", err)
}
// 将队列转换为切片
res := make([]string, 0, num)
for e := data1.Front(); e != nil; e = e.Next() {
res = append(res, e.Value.(string))
}
return res
二、逆向读取
使用文件指针,从文件的末尾开始读取。我们可以使用os包的Seek函数来定位文件的末尾,然后逐行向上读取,直到读取到100行。
stats, statsErr := file.Stat()
if statsErr != nil {
return nil
}
size := stats.Size()
lines := make([]string, 0, num)
buf := make([]byte, size)
for {
readSize, err := file.ReadAt(buf, size-int64(len(buf)))
if err != nil && err != io.EOF {
break
}
size -= int64(readSize)
for i := readSize - 1; i >= 0; i-- {
if buf[i] == '\n' {
lines = append(lines, string(buf[i+1:readSize]))
readSize = i
if len(lines) == num {
return lines
}
}
}
if size == 0 {
lines = append(lines, string(buf[:readSize]))
break
}
if len(lines) >= num {
break
}
if size < int64(len(buf)) {
buf = make([]byte, size)
}
}
return lines