反向读取文件

w1281472252 · · 1187 次点击
最后一轮不输出是因为没有输入换行,在buff函数结束前加入下面的判断就能解决。缓存没必要动态创建,这样会频繁在的堆上创建对象,增加内存碎片和GC压力。 ```go if offset == 0 { _, err = c.bwr.Write([]byte{'\n'}) if err != nil { return err } } ```
#4
更多评论
请问这样做的需求是什么?可以试试:先读取文件,然后转为string后,反转一下?
#1
临时写了一个,测试了一下可以,如用于生产环境的话还需要严格测试。 ```go package file import ( "bytes" "fmt" "io" "os" ) var ( buffSize = 1 << 20 ) // ReadLineFromEnd -- type ReadLineFromEnd struct { f *os.File fileSize int bwr *bytes.Buffer swapBuff []byte } // NewReadLineFromEnd -- func NewReadLineFromEnd(name string) (rd *ReadLineFromEnd, err error) { f, err := os.Open(name) if err != nil { return nil, err } info, err := f.Stat() if info.IsDir() { return nil, fmt.Errorf("not file") } fileSize := int(info.Size()) rd = &ReadLineFromEnd{ f: f, fileSize: fileSize, bwr: bytes.NewBuffer([]byte{}), swapBuff: make([]byte, buffSize), } return rd, nil } // Read -- func (c *ReadLineFromEnd) Read(p []byte) (n int, err error) { err = c.buff() if err != nil { return n, err } return c.bwr.Read(p) } // ReadLine 结尾包含'\n' func (c *ReadLineFromEnd) ReadLine() (line []byte, err error) { err = c.buff() if err != nil { return nil, err } return c.bwr.ReadBytes('\n') } // Close -- func (c *ReadLineFromEnd) Close() (err error) { return c.f.Close() } func (c *ReadLineFromEnd) buff() (err error) { if c.fileSize == 0 { return nil } if c.bwr.Len() >= buffSize { return nil } offset := 0 if c.fileSize > buffSize { offset = c.fileSize - buffSize } _, err = c.f.Seek(int64(offset), 0) if err != nil { return err } n, err := c.f.Read(c.swapBuff) if err != nil && err != io.EOF { return err } if n == 0 { return nil } for { m := bytes.LastIndex(c.swapBuff[:n], []byte{'\n'}) if m == -1 { break } if m < n-1 { _, err = c.bwr.Write(c.swapBuff[m+1 : n]) if err != nil { return err } _, err = c.bwr.Write([]byte{'\n'}) if err != nil { return err } } n = m if n == 0 { break } } if n > 0 { _, err := c.bwr.Write(c.swapBuff[:n]) if err != nil { return err } } c.fileSize = offset return nil } ``` 测试代码 ```go func TestNewReadLineFromEnd(t *testing.T) { rd, err := NewReadLineFromEnd("./123.log") if err != nil { t.Fatal(err) } defer rd.Close() for { data, err := rd.ReadLine() if err != nil { if err != io.EOF { t.Fatal(err) } break } fmt.Print(string(data)) } } ```
#2