我需要为现有的子io.Reader创建一个缓冲读取器,但是该读取器必须支持在已经从子读取并缓冲的数据中查找。因此,当已经读取了n字节时,我希望能够将读取器重置为偏移量0,并再次读取该块。不幸的是bufio.Reader不支持查找。是否有标准的阅读器支持这一点,或者我必须实现自己的阅读器?
io.Reader
n
0
bufio.Reader
7uzetpgm1#
bufio的目的是提供缓冲I/O。缓冲I/O旨在提高性能,而不是时间旅行。您只需将数据读入字节片,然后使用bytes.Reader进一步处理它。
bufio
bytes.Reader
mwngjboj2#
我想知道在打开的os.File中查找,然后使用bufio.Reset()是否是一个答案,它算是,但并不理想。首先,bufio.Reset的文档说它“丢弃任何缓冲数据”,但话又说回来,操作系统不也缓存最近读取的文件内容吗?第二,从bufio从指定的文件位置开始阅读和缓冲的意义上说,它工作正常,但它不考虑扇区对齐:它一次缓冲整个缓冲区,而不管起始点。因此,假设缓冲区大小为(默认为4096)等于文件系统的簇大小,除非起点对齐簇,否则bufio每次需要读取时都会从2个簇读取,我并不是说对性能的影响是显而易见的,实际上,通过尽可能提前阅读,性能可能比我的对齐痴迷可能产生的更好。我认为这段代码演示了这一点,从可执行文件本身阅读了几个2000字节的块:
os.File
bufio.Reset()
bufio.Reset
package main import ( "bufio" "crypto/md5" "fmt" "os" ) func readBytes(r *bufio.Reader, block []byte) { for i := 1; i < len(block); i++ { var err error block[i], err = r.ReadByte() if err != nil { panic(err) } } } func status(f *os.File, r *bufio.Reader, block []byte, what string) { fpos, err := f.Seek(0, os.SEEK_CUR) if err != nil { panic(err) } fmt.Printf("%s: fpos=%5d, buffered=%4d, md5=%X\n", what, fpos, r.Buffered(), md5.Sum(block)) } func main() { f, err := os.Open(os.Args[0]) if err != nil { panic(err) } defer func() { f.Close() }() r := bufio.NewReader(f) var block = make([]byte, 2000) status(f, r, block, "initial") readBytes(r, block) status(f, r, block, "block 1") readBytes(r, block) status(f, r, block, "block 2") readBytes(r, block) status(f, r, block, "block 3") f.Seek(2000, os.SEEK_SET) // return to start of buf1a r.Reset(f) readBytes(r, block) status(f, r, block, "block 2") readBytes(r, block) status(f, r, block, "block 3") readBytes(r, block) status(f, r, block, "block 4") }
典型输出(显示在查找后,文件位置没有返回到4096的倍数):
initial: fpos= 0, buffered= 0, md5=CF40A1DE3F93B4A025409B5EFA5AA210 block 1: fpos= 4096, buffered=2096, md5=C7015DD984AB85CCCBD206BA8243647D block 2: fpos= 4096, buffered= 96, md5=E0D75F4A6DE681316515F5CD53F0D95C block 3: fpos= 8192, buffered=2192, md5=7961B1A889E9793344374B3022314CD0 block 2: fpos= 6096, buffered=2096, md5=E0D75F4A6DE681316515F5CD53F0D95C block 3: fpos= 6096, buffered= 96, md5=7961B1A889E9793344374B3022314CD0 block 4: fpos=10192, buffered=2192, md5=2A2F77C23EF4651E630855D9C3AA29DE
2条答案
按热度按时间7uzetpgm1#
bufio
的目的是提供缓冲I/O。缓冲I/O旨在提高性能,而不是时间旅行。您只需将数据读入字节片,然后使用
bytes.Reader
进一步处理它。mwngjboj2#
我想知道在打开的
os.File
中查找,然后使用bufio.Reset()
是否是一个答案,它算是,但并不理想。首先,bufio.Reset
的文档说它“丢弃任何缓冲数据”,但话又说回来,操作系统不也缓存最近读取的文件内容吗?第二,从bufio从指定的文件位置开始阅读和缓冲的意义上说,它工作正常,但它不考虑扇区对齐:它一次缓冲整个缓冲区,而不管起始点。因此,假设缓冲区大小为(默认为4096)等于文件系统的簇大小,除非起点对齐簇,否则bufio每次需要读取时都会从2个簇读取,我并不是说对性能的影响是显而易见的,实际上,通过尽可能提前阅读,性能可能比我的对齐痴迷可能产生的更好。
我认为这段代码演示了这一点,从可执行文件本身阅读了几个2000字节的块:
典型输出(显示在查找后,文件位置没有返回到4096的倍数):