When reading a file, we usually read from the front to the back. What if we want to read the last line of the file?

Read sequentially until the last line of the file
public static String readLastLineV0(File file) {
  String lastLine = "";
  try (BufferedReader bufferedReader = new BufferedReader(new FileReader(file))) {
    String currentLine = "";
    while((currentLine = bufferedReader.readLine()) ! =null) { lastLine = currentLine; }}catch (Exception e) {
    log.error("file read error, msg:{}", e.getMessage(), e);
  }

  return lastLine;
}
Copy the code

This is simple, just read from front to back until the last line.

Use RandomAccessFile to specify the location and read from back to forward
public static String readLastLineV1(File file) {
  // Store the result
  StringBuilder builder = new StringBuilder();
  try (RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r")) {
    // The pointer position starts at 0, so the maximum length is length-1
    long fileLastPointer = randomAccessFile.length() - 1;
    // Read files from back to forward
    for (longfilePointer = fileLastPointer; filePointer ! = -1; filePointer--) {
      // Move the pointer pointer
      randomAccessFile.seek(filePointer);
      int readByte = randomAccessFile.readByte();
      if (0xA == readByte) {
        / / LF = '\ n' = 0 x0a newline
        if (filePointer == fileLastPointer) {
          // If it is the last line break, filter it out
          continue;
        }
        break;
      }
      if (0xD == readByte) {
        // CR ='\r'=0x0D
        if (filePointer == fileLastPointer - 1) {
          // If the return is reciprocal, filter it out
          continue;
        }
        break;
      }
      builder.append((char) readByte); }}catch (Exception e) {
    log.error("file read error, msg:{}", e.getMessage(), e);
  }
  return builder.reverse().toString();
}
Copy the code

The method is mainly the use of RandomAccessFile can seek to the specified location read way. Read forward from the end of the file. When 0xA (newline) or 0xD (carriage return) is encountered, StringBuilder caches the read data and reverses the data to the last row.

Use the ReversedLinesFileReader in Commons-io

Maven import dependency

<dependency>
  <groupId>commons-io</groupId>
  <artifactId>commons-io</artifactId>
  <version>2.7</version>
</dependency>
Copy the code
public static String readLastLineV2(File file) {
  String lastLine = "";
  try (ReversedLinesFileReader reversedLinesReader = new ReversedLinesFileReader(file, Charset.defaultCharset())) {
    lastLine = reversedLinesReader.readLine();
  } catch (Exception e) {
    log.error("file read error, msg:{}", e.getMessage(), e);
  }
  return lastLine;
}
Copy the code

In this mode, the data can be read directly to the last row. Interested students can take a look at the source code, very few. The idea is to split a file into multiple FileParts. Read position positioning is based on the Position method of SeekableByteChannel. In FilePart’s readLine implementation, multiple bytes can be read at once.

conclusion

Of the above three methods for reading the last line of a file, the ReversedLinesFileReader in Commons-io is recommended and is relatively simple to use.