Golang中的bufio.NewScanner是否在内存中读取整个文件而不是每行?

时间:2016-08-11 16:52:12

标签: file go offset seek

我试图使用bufio.NewScanner逐行读取文件,使用以下函数。

func TailFromStart(fd *os.File, wg *sync.WaitGroup)  {

    fd.Seek(0,0)
    scanner := bufio.NewScanner(fd)
    for scanner.Scan() {
        line := scanner.Text()
        offset, _ := fd.Seek(0, 1)
        fmt.Println(offset)
        fmt.Println(line)
        offsetreset, _ := fd.Seek(offset, 0)
        fmt.Println(offsetreset)
    }
    offset, err := fd.Seek(0, 1)
    CheckError(err)
    fmt.Println(offset)
    wg.Done()

}

我希望它按递增顺序打印偏移量,但是,它会在每次迭代中打印相同的值,直到文件达到EOF

127.0.0.1 - - [11/Aug/2016:22:10:39 +0530] "GET /ttt HTTP/1.1" 404 437 "-" "curl/7.38.0"
613
613
127.0.0.1 - - [11/Aug/2016:22:10:42 +0530] "GET /qqq HTTP/1.1" 404 437 "-" "curl/7.38.0"
613

613是文件中的总字符数。

cat /var/log/apache2/access.log | wc
  7      84     613

我是否理解错误,或者bufio.NewScanner是否在内存中读取整个文件,并在内存中进行迭代?如果是这样,有没有更好的方法逐行阅读?

2 个答案:

答案 0 :(得分:4)

请参阅func (s *Scanner) Buffer(buf []byte, max int)文档:

  

缓冲区设置扫描时使用的初始缓冲区和最大值   扫描期间可能分配的缓冲区大小。最大值   令牌大小是max和cap(buf)中的较大者   如果是max <= cap(buf),   扫描仅使用此缓冲区,不进行分配。

     

默认情况下,Scan使用内部缓冲区并设置最大令牌   大小为MaxScanTokenSize

     

如果在扫描开始后调用它,则缓冲区会发生混乱。

  

MaxScanTokenSize是用于缓冲令牌的最大大小,除非   用户使用Scan.Buffer提供显式缓冲区。实际上   最大令牌大小可能会更小,因为缓冲区可能需要包括,   例如,换行符。

MaxScanTokenSize = 64 * 1024

startBufSize = 4096 // Size of initial allocation for buffer.

不,因为@JimB说它只读取缓冲区大小,请参阅此测试样本:

对于小于4096字节,它将所有文件内容读入缓冲区,
但对于大文件,只读取4096字节,
尝试使用大文件:

package main

import (
    "bufio"
    "fmt"
    "os"
)

func main() {
    fd, err := os.Open("big.txt")
    if err != nil {
        panic(err)
    }
    defer fd.Close()

    n, err := fd.Seek(0, 0)
    if err != nil {
        panic(err)
    }
    fmt.Println("n =", n) // 0

    scanner := bufio.NewScanner(fd)
    for scanner.Scan() {
        fmt.Println(scanner.Text())
        break
    }

    offset, err := fd.Seek(0, 1)
    if err != nil {
        panic(err)
    }
    fmt.Println("offset =", offset) //4096

    offsetreset, err := fd.Seek(offset, 0)
    if err != nil {
        panic(err)
    }
    fmt.Println("offsetreset =", offsetreset) //4096

    offset, err = fd.Seek(0, 1)
    if err != nil {
        panic(err)
    }
    fmt.Println("offset =", offset) //4096

}

输出:

n = 0

offset = 4096
offsetreset = 4096
offset = 4096

答案 1 :(得分:0)

您可以增加扫描仪的缓冲区大小

例如:-

scanner := bufio.NewScanner(file)
buf := make([]byte, 0, 64*1024)
scanner.Buffer(buf, 1024*1024) //1024*1024 => 1mb max (you can change value here to read larger files
for scanner.Scan() {
    // do your stuff
}