...
1
16
17 package tail
18
19 import (
20 "bytes"
21 "io"
22 "os"
23 )
24
25 const (
26
27 blockSize = 1024
28 )
29
30 var (
31
32 eol = []byte{'\n'}
33 )
34
35
36
37
38 func ReadAtMost(path string, max int64) ([]byte, bool, error) {
39 f, err := os.Open(path)
40 if err != nil {
41 return nil, false, err
42 }
43 defer f.Close()
44 fi, err := f.Stat()
45 if err != nil {
46 return nil, false, err
47 }
48 size := fi.Size()
49 if size == 0 {
50 return nil, false, nil
51 }
52 if size < max {
53 max = size
54 }
55 offset, err := f.Seek(-max, io.SeekEnd)
56 if err != nil {
57 return nil, false, err
58 }
59 data, err := io.ReadAll(f)
60 return data, offset > 0, err
61 }
62
63
64
65
66
67
68 func FindTailLineStartIndex(f io.ReadSeeker, n int64) (int64, error) {
69 if n < 0 {
70 return 0, nil
71 }
72 size, err := f.Seek(0, io.SeekEnd)
73 if err != nil {
74 return 0, err
75 }
76 var left, cnt int64
77 buf := make([]byte, blockSize)
78 for right := size; right > 0 && cnt <= n; right -= blockSize {
79 left = right - blockSize
80 if left < 0 {
81 left = 0
82 buf = make([]byte, right)
83 }
84 if _, err := f.Seek(left, io.SeekStart); err != nil {
85 return 0, err
86 }
87 if _, err := f.Read(buf); err != nil {
88 return 0, err
89 }
90 cnt += int64(bytes.Count(buf, eol))
91 }
92 for ; cnt > n; cnt-- {
93 idx := bytes.Index(buf, eol) + 1
94 buf = buf[idx:]
95 left += int64(idx)
96 }
97 return left, nil
98 }
99
View as plain text