ReadTailLines reads the last lineCount lines from a file, excluding the last lineOffset lines. It progressively reads larger windows from the end of the file (starting at 1MB, doubling up to readLimit) until it finds enough lines or reaches the limit. Returns the lines, stop reason, and any error. S
(file *os.File, lineCount int, lineOffset int, readLimit int64)
| 145 | // Stop reason is StopReasonBOF when beginning of file is reached, StopReasonReadLimit when byte limit is reached, |
| 146 | // or empty string for natural completion (found requested line count). |
| 147 | func ReadTailLines(file *os.File, lineCount int, lineOffset int, readLimit int64) ([]string, string, error) { |
| 148 | if readLimit <= 0 { |
| 149 | return nil, "", fmt.Errorf("ReadTailLines readLimit must be positive, got %d", readLimit) |
| 150 | } |
| 151 | |
| 152 | fileInfo, err := file.Stat() |
| 153 | if err != nil { |
| 154 | return nil, "", err |
| 155 | } |
| 156 | fileSize := fileInfo.Size() |
| 157 | |
| 158 | readBytes := int64(1024 * 1024) |
| 159 | if readLimit < readBytes { |
| 160 | readBytes = readLimit |
| 161 | } |
| 162 | |
| 163 | for { |
| 164 | startPos := fileSize - readBytes |
| 165 | if startPos < 0 { |
| 166 | startPos = 0 |
| 167 | readBytes = fileSize |
| 168 | } |
| 169 | |
| 170 | sectionReader := io.NewSectionReader(file, startPos, readBytes) |
| 171 | keepFirst := startPos == 0 |
| 172 | |
| 173 | lines, hasMoreInWindow, err := readTailLinesInternal(sectionReader, lineCount, lineOffset, keepFirst) |
| 174 | if err != nil { |
| 175 | return nil, "", err |
| 176 | } |
| 177 | |
| 178 | if len(lines) == lineCount { |
| 179 | hasMore := startPos > 0 || hasMoreInWindow |
| 180 | if !hasMore { |
| 181 | return lines, StopReasonBOF, nil |
| 182 | } |
| 183 | return lines, "", nil |
| 184 | } |
| 185 | |
| 186 | if readBytes >= readLimit || readBytes >= fileSize { |
| 187 | if startPos > 0 { |
| 188 | return lines, StopReasonReadLimit, nil |
| 189 | } |
| 190 | return lines, StopReasonBOF, nil |
| 191 | } |
| 192 | |
| 193 | readBytes *= 2 |
| 194 | if readBytes > readLimit { |
| 195 | readBytes = readLimit |
| 196 | } |
| 197 | } |
| 198 | } |
no test coverage detected