123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- package file
- import (
- "bytes"
- "fmt"
- "io"
- "os"
- )
- var (
- buffSize = 1 << 20
- )
- // ReadLineFromEnd --
- type ReadLineFromEnd struct {
- f *os.File
- fileSize int
- bwr *bytes.Buffer
- lineBuff []byte
- swapBuff []byte
- isFirst bool
- }
- // Exists
- func IsExists(path string) (os.FileInfo, bool) {
- f, err := os.Stat(path)
- return f, err == nil || os.IsExist(err)
- }
- // NewReadLineFromEnd
- func NewReadLineFromEnd(filename string) (rd *ReadLineFromEnd, err error) {
- f, err := os.Open(filename)
- if err != nil {
- return nil, err
- }
- info, err := f.Stat()
- if err != nil {
- return nil, err
- }
- if info.IsDir() {
- return nil, fmt.Errorf("not file")
- }
- fileSize := int(info.Size())
- rd = &ReadLineFromEnd{
- f: f,
- fileSize: fileSize,
- bwr: bytes.NewBuffer([]byte{}),
- lineBuff: make([]byte, 0),
- swapBuff: make([]byte, buffSize),
- isFirst: true,
- }
- return rd, nil
- }
- // ReadLine 结尾包含'\n'
- func (c *ReadLineFromEnd) ReadLine() (line []byte, err error) {
- var ok bool
- for {
- ok, err = c.buff()
- if err != nil {
- return nil, err
- }
- if ok {
- break
- }
- }
- line, err = c.bwr.ReadBytes('\n')
- if err == io.EOF && c.fileSize > 0 {
- err = nil
- }
- return line, err
- }
- // Close --
- func (c *ReadLineFromEnd) Close() (err error) {
- return c.f.Close()
- }
- func (c *ReadLineFromEnd) buff() (ok bool, err error) {
- if c.fileSize == 0 {
- return true, nil
- }
- if c.bwr.Len() >= buffSize {
- return true, nil
- }
- offset := 0
- if c.fileSize > buffSize {
- offset = c.fileSize - buffSize
- }
- _, err = c.f.Seek(int64(offset), 0)
- if err != nil {
- return false, err
- }
- n, err := c.f.Read(c.swapBuff)
- if err != nil && err != io.EOF {
- return false, err
- }
- if c.fileSize < n {
- n = c.fileSize
- }
- if n == 0 {
- return true, nil
- }
- for {
- m := bytes.LastIndex(c.swapBuff[:n], []byte{'\n'})
- if m == -1 {
- break
- }
- if m < n-1 {
- err = c.writeLine(c.swapBuff[m+1 : n])
- if err != nil {
- return false, err
- }
- ok = true
- } else if m == n-1 && !c.isFirst {
- err = c.writeLine(nil)
- if err != nil {
- return false, err
- }
- ok = true
- }
- n = m
- if n == 0 {
- break
- }
- }
- if n > 0 {
- reverseBytes(c.swapBuff[:n])
- c.lineBuff = append(c.lineBuff, c.swapBuff[:n]...)
- }
- if offset == 0 {
- err = c.writeLine(nil)
- if err != nil {
- return false, err
- }
- ok = true
- }
- c.fileSize = offset
- if c.isFirst {
- c.isFirst = false
- }
- return ok, nil
- }
- func (c *ReadLineFromEnd) writeLine(b []byte) (err error) {
- if len(b) > 0 {
- _, err = c.bwr.Write(b)
- if err != nil {
- return err
- }
- }
- if len(c.lineBuff) > 0 {
- reverseBytes(c.lineBuff)
- _, err = c.bwr.Write(c.lineBuff)
- if err != nil {
- return err
- }
- c.lineBuff = c.lineBuff[:0]
- }
- _, err = c.bwr.Write([]byte{'\n'})
- if err != nil {
- return err
- }
- return nil
- }
- func reverseBytes(b []byte) {
- n := len(b)
- if n <= 1 {
- return
- }
- for i := 0; i < n; i++ {
- k := n - 1
- if k != i {
- b[i], b[k] = b[k], b[i]
- }
- n--
- }
- }
|