The following is a patch against 2.0.1 in SVN which seems to address the
limitation:
Index: src/main/java/org/apache/commons/io/input/Tailer.java
===================================================================
--- src/main/java/org/apache/commons/io/input/Tailer.java (revision 1127267)
+++ src/main/java/org/apache/commons/io/input/Tailer.java (working copy)
@@ -335,12 +335,56 @@
* @throws java.io.IOException if an I/O error occurs.
*/
private long readLines(RandomAccessFile reader) throws IOException {
- String line = reader.readLine();
+ String line = readLine(reader);
while (line != null) {
listener.handle(line);
- line = reader.readLine();
+ line = readLine(reader);
}
return reader.getFilePointer();
}
+ /**
+ * Copied from RandomAccessFile.readLine() but returns null and resets
file pointer on EOF.
+ * @param reader
+ * @return
+ * @throws IOException
+ */
+ private final String readLine(RandomAccessFile reader) throws
IOException {
+ long start = reader.getFilePointer();
+ StringBuffer input = new StringBuffer();
+ int c = -1;
+ boolean eol = false;
+ boolean eof = false;
+
+ while (!eol && !eof) {
+ switch (c = reader.read()) {
+ case -1:
+ eof = true;
+ break;
+ case '\n':
+ eol = true;
+ break;
+ case '\r':
+ eol = true;
+ long cur = reader.getFilePointer();
+ if ((reader.read()) != '\n') {
+ reader.seek(cur);
+ }
+ break;
+ default:
+ input.append((char)c);
+ break;
+ }
+ }
+
+ if ((c == -1) && (input.length() == 0)) {
+ return null;
+ }
+ if (eof) {
+ reader.seek(start);
+ return null;
+ }
+
+ return input.toString();
+ }
}
Index: src/test/java/org/apache/commons/io/input/TailerTest.java
===================================================================
--- src/test/java/org/apache/commons/io/input/TailerTest.java (revision
1127267)
+++ src/test/java/org/apache/commons/io/input/TailerTest.java (working copy)
@@ -45,6 +45,38 @@
protected void tearDown() throws Exception {
FileUtils.deleteDirectory(getTestDirectory());
}
+
+ public void testTailerEof() throws Exception {
+ // Create & start the Tailer
+ long delay = 50;
+ final File file = new File(getTestDirectory(), "tailer2-test.txt");
+ createFile(file, 0);
+ final TestTailerListener listener = new TestTailerListener();
+ final Tailer tailer = new Tailer(file, listener, delay, false);
+ final Thread thread = new Thread(tailer);
+ thread.start();
+
+ // Write some lines to the file
+ FileWriter writer = null;
+ try {
+ writeString(file, "Line");
+
+ Thread.sleep(delay * 2);
+ List<String> lines = listener.getLines();
+ assertEquals("1 line count", 0, lines.size());
+
+ writeString(file, " one\n");
+ Thread.sleep(delay * 2);
+ lines = listener.getLines();
+
+ assertEquals("1 line count", 1, lines.size());
+ assertEquals("1 line 1", "Line one", lines.get(0));
+
+ listener.clear();
+ } finally {
+ IOUtils.closeQuietly(writer);
+ }
+ }
public void testTailer() throws Exception {
@@ -142,6 +174,17 @@
IOUtils.closeQuietly(writer);
}
}
+
+ /** Append a string to a file */
+ private void writeString(File file, String string) throws Exception {
+ FileWriter writer = null;
+ try {
+ writer = new FileWriter(file, true);
+ writer.write(string);
+ } finally {
+ IOUtils.closeQuietly(writer);
+ }
+ }
public void testStopWithNoFile() throws Exception {
final File file = new File(getTestDirectory(),"nosuchfile");
On Tue, May 24, 2011 at 1:32 PM, frankgrimes97 <[email protected]>wrote:
> Hi All,
>
> We are using org.apache.commons.io.input.Tailer to process log files for
> insertion into a database.
>
> What we are seeing is that occasionally a line fails to process because it
> is incomplete.
> In reviewing the code, it appears that Tailer.readLines delegates to
> java.io.RandomAccessFile.readLine which returns a partial line if EOF is
> reached.
>
> Shouldn't Tailer be providing a guarantee of complete lines?
> Should we create a bug report for this?
>
> FYI, we are using 1.6.0_15 on Linux.
>
> Thanks,
>
> Frank Grimes
>