FindTailLineStartIndex returns the start of last nth line. * If n <= 0, return the beginning of the file. * If n > 0, return the beginning of last nth line. Notice that if the last line is incomplete (no end-of-line), it will not be counted as one line.
(f io.ReadSeeker, n uint)
| 43 | // Notice that if the last line is incomplete (no end-of-line), it will not be counted |
| 44 | // as one line. |
| 45 | func FindTailLineStartIndex(f io.ReadSeeker, n uint) (int64, error) { |
| 46 | if n <= 0 { |
| 47 | return 0, nil |
| 48 | } |
| 49 | size, err := f.Seek(0, io.SeekEnd) |
| 50 | if err != nil { |
| 51 | return 0, err |
| 52 | } |
| 53 | var left, cnt int64 |
| 54 | buf := make([]byte, blockSize) |
| 55 | for right := size; right > 0 && uint(cnt) <= n; right -= blockSize { |
| 56 | left = right - blockSize |
| 57 | if left < 0 { |
| 58 | left = 0 |
| 59 | buf = make([]byte, right) |
| 60 | } |
| 61 | if _, err := f.Seek(left, io.SeekStart); err != nil { |
| 62 | return 0, err |
| 63 | } |
| 64 | if _, err := f.Read(buf); err != nil { |
| 65 | return 0, err |
| 66 | } |
| 67 | cnt += int64(bytes.Count(buf, eol)) |
| 68 | } |
| 69 | for ; uint(cnt) > n; cnt-- { |
| 70 | idx := bytes.Index(buf, eol) + 1 |
| 71 | buf = buf[idx:] |
| 72 | left += int64(idx) |
| 73 | } |
| 74 | return left, nil |
| 75 | } |