diff --git a/src/main/java/org/apache/commons/io/input/ReversedLinesFileReader.java b/src/main/java/org/apache/commons/io/input/ReversedLinesFileReader.java index cd883af9adb..808769844c4 100644 --- a/src/main/java/org/apache/commons/io/input/ReversedLinesFileReader.java +++ b/src/main/java/org/apache/commons/io/input/ReversedLinesFileReader.java @@ -39,7 +39,9 @@ import org.apache.commons.io.build.AbstractStreamBuilder; /** - * Reads lines in a file reversely (similar to a BufferedReader, but starting at the last line). Useful for e.g. searching in log files. + * Reads lines in a file in reverse (similar to a BufferedReader, but starting at the last line). + * Line endings (\n, \r) are not included in the lines returned. + * Useful for e.g. searching in log files. *
* To build an instance, use {@link Builder}. *
@@ -108,7 +110,7 @@ public ReversedLinesFileReader get() throws IOException { } private final class FilePart { - private final long no; + private final long partNumber; private final byte[] data; @@ -119,20 +121,20 @@ private final class FilePart { /** * Constructs a new instance. * - * @param no the part number + * @param partNumber the part number * @param length its length * @param leftOverOfLastFilePart remainder * @throws IOException if there is a problem reading the file */ - private FilePart(final long no, final int length, final byte[] leftOverOfLastFilePart) throws IOException { - this.no = no; + private FilePart(final long partNumber, final int length, final byte[] leftOverOfLastFilePart) throws IOException { + this.partNumber = partNumber; final int dataLength = length + (leftOverOfLastFilePart != null ? leftOverOfLastFilePart.length : 0); this.data = new byte[dataLength]; - final long off = (no - 1) * blockSize; + final long offset = (partNumber - 1) * blockSize; // read data - if (no > 0 /* file not empty */) { - channel.position(off); + if (partNumber > 0 /* file not empty */) { + channel.position(offset); final int countRead = channel.read(ByteBuffer.wrap(data, 0, length)); if (countRead != length) { throw new IllegalStateException("Count of requested bytes and actually read bytes don't match"); @@ -191,7 +193,7 @@ private String readLine() { //NOPMD Bug in PMD String line = null; int newLineMatchByteCount; - final boolean isLastFilePart = no == 1; + final boolean isLastFilePart = partNumber == 1; int i = currentLastBytePos; while (i > -1) { @@ -252,8 +254,8 @@ private FilePart rollOver() throws IOException { + "last readLine() should have returned something! currentLastCharPos=" + currentLastBytePos); } - if (no > 1) { - return new FilePart(no - 1, blockSize, leftOver); + if (partNumber > 1) { + return new FilePart(partNumber - 1, blockSize, leftOver); } // NO 1 was the last FilePart, we're finished if (leftOver != null) { diff --git a/src/test/java/org/apache/commons/io/input/ReversedLinesFileReaderTestSimple.java b/src/test/java/org/apache/commons/io/input/ReversedLinesFileReaderTestSimple.java index e8c5b0ecbb1..909404a6b49 100644 --- a/src/test/java/org/apache/commons/io/input/ReversedLinesFileReaderTestSimple.java +++ b/src/test/java/org/apache/commons/io/input/ReversedLinesFileReaderTestSimple.java @@ -34,11 +34,12 @@ public class ReversedLinesFileReaderTestSimple { + private final int BLOCK_SIZE = 10; + @Test public void testFileSizeIsExactMultipleOfBlockSize() throws URISyntaxException, IOException { - final int blockSize = 10; final File testFile20Bytes = TestResources.getFile("/test-file-20byteslength.bin"); - try (ReversedLinesFileReader reversedLinesFileReader = new ReversedLinesFileReader(testFile20Bytes, blockSize, + try (ReversedLinesFileReader reversedLinesFileReader = new ReversedLinesFileReader(testFile20Bytes, BLOCK_SIZE, StandardCharsets.ISO_8859_1.name())) { assertEqualsAndNoLineBreaks("987654321", reversedLinesFileReader.readLine()); assertEqualsAndNoLineBreaks("123456789", reversedLinesFileReader.readLine()); @@ -47,9 +48,8 @@ public void testFileSizeIsExactMultipleOfBlockSize() throws URISyntaxException, @Test public void testLineCount() throws URISyntaxException, IOException { - final int blockSize = 10; final File testFile20Bytes = TestResources.getFile("/test-file-20byteslength.bin"); - try (ReversedLinesFileReader reversedLinesFileReader = new ReversedLinesFileReader(testFile20Bytes, blockSize, + try (ReversedLinesFileReader reversedLinesFileReader = new ReversedLinesFileReader(testFile20Bytes, BLOCK_SIZE, StandardCharsets.ISO_8859_1.name())) { assertThrows(IllegalArgumentException.class, () -> reversedLinesFileReader.readLines(-1)); assertTrue(reversedLinesFileReader.readLines(0).isEmpty()); @@ -63,9 +63,8 @@ public void testLineCount() throws URISyntaxException, IOException { @Test public void testToString() throws URISyntaxException, IOException { - final int blockSize = 10; final File testFile20Bytes = TestResources.getFile("/test-file-20byteslength.bin"); - try (ReversedLinesFileReader reversedLinesFileReader = new ReversedLinesFileReader(testFile20Bytes, blockSize, + try (ReversedLinesFileReader reversedLinesFileReader = new ReversedLinesFileReader(testFile20Bytes, BLOCK_SIZE, StandardCharsets.ISO_8859_1.name())) { assertThrows(IllegalArgumentException.class, () -> reversedLinesFileReader.toString(-1)); assertTrue(reversedLinesFileReader.readLines(0).isEmpty()); @@ -90,4 +89,17 @@ public void testUnsupportedEncodingUTF16() throws URISyntaxException { () -> new ReversedLinesFileReader(testFileEmpty, IOUtils.DEFAULT_BUFFER_SIZE, StandardCharsets.UTF_16.name()).close()); } + @Test + // IO-639 + public void testEmptyFirstLine() throws IOException, URISyntaxException { + final File testFileEmptyFirstLine = TestResources.getFile("/empty_first_line.bin"); + try (ReversedLinesFileReader reversedLinesFileReader = new ReversedLinesFileReader(testFileEmptyFirstLine, BLOCK_SIZE, + StandardCharsets.US_ASCII.name())) { + assertEqualsAndNoLineBreaks("test2", reversedLinesFileReader.readLine()); + assertEqualsAndNoLineBreaks("", reversedLinesFileReader.readLine()); + assertEqualsAndNoLineBreaks("test1", reversedLinesFileReader.readLine()); + assertEqualsAndNoLineBreaks("", reversedLinesFileReader.readLine()); + } + } + } diff --git a/src/test/resources/org/apache/commons/io/empty_first_line.bin b/src/test/resources/org/apache/commons/io/empty_first_line.bin new file mode 100644 index 00000000000..4e0e6422d38 --- /dev/null +++ b/src/test/resources/org/apache/commons/io/empty_first_line.bin @@ -0,0 +1,4 @@ + +test1 + +test2