Skip to content

Commit 8d52f69

Browse files
committed
IO-354 Commons IO Tailer does not respect UTF-8 Charset
git-svn-id: https://svn.apache.org/repos/asf/commons/proper/io/trunk@1468703 13f79535-47bb-0310-9956-ffa450edef68
1 parent b614ab5 commit 8d52f69

3 files changed

Lines changed: 54 additions & 11 deletions

File tree

src/changes/changes.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ The <action> type attribute can be add,update,fix,remove.
4747
<body>
4848
<!-- The release date is the date RC is cut -->
4949
<release version="2.5" date="2013-??-??" description="New features and bug fixes.">
50+
<action issue="IO-354" dev="sebb" type="fix">
51+
Commons IO Tailer does not respect UTF-8 Charset.
52+
</action>
5053
<action issue="IO-323" dev="sebb" type="fix">
5154
What should happen in FileUtils.sizeOf[Directory] when an overflow takes place?
5255
Added Javadoc.

src/main/java/org/apache/commons/io/input/Tailer.java

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@
1616
*/
1717
package org.apache.commons.io.input;
1818

19+
import java.io.ByteArrayOutputStream;
1920
import java.io.File;
2021
import java.io.FileNotFoundException;
2122
import java.io.IOException;
2223
import java.io.RandomAccessFile;
24+
import java.nio.charset.Charset;
2325

2426
import org.apache.commons.io.FileUtils;
2527
import org.apache.commons.io.IOUtils;
@@ -444,11 +446,11 @@ public void stop() {
444446
* @throws java.io.IOException if an I/O error occurs.
445447
*/
446448
private long readLines(final RandomAccessFile reader) throws IOException {
447-
final StringBuilder sb = new StringBuilder();
448-
449+
// Make explicit that the default charset is being used here
450+
Charset cset = Charset.defaultCharset();
451+
ByteArrayOutputStream lineBuf = new ByteArrayOutputStream(64);
449452
long pos = reader.getFilePointer();
450453
long rePos = pos; // position to re-read
451-
452454
int num;
453455
boolean seenCR = false;
454456
while (getRun() && ((num = reader.read(inbuf)) != -1)) {
@@ -457,30 +459,29 @@ private long readLines(final RandomAccessFile reader) throws IOException {
457459
switch (ch) {
458460
case '\n':
459461
seenCR = false; // swallow CR before LF
460-
listener.handle(sb.toString());
461-
sb.setLength(0);
462+
listener.handle(new String(lineBuf.toByteArray(), cset));
463+
lineBuf.reset();
462464
rePos = pos + i + 1;
463465
break;
464466
case '\r':
465467
if (seenCR) {
466-
sb.append('\r');
468+
lineBuf.write('\r');
467469
}
468470
seenCR = true;
469471
break;
470472
default:
471473
if (seenCR) {
472474
seenCR = false; // swallow final CR
473-
listener.handle(sb.toString());
474-
sb.setLength(0);
475+
listener.handle(new String(lineBuf.toByteArray(), cset));
476+
lineBuf.reset();
475477
rePos = pos + i + 1;
476478
}
477-
sb.append((char) ch); // add character, not its ascii value
479+
lineBuf.write(ch);
478480
}
479481
}
480-
481482
pos = reader.getFilePointer();
482483
}
483-
484+
IOUtils.closeQuietly(lineBuf); // not strictly necessary
484485
reader.seek(rePos); // Ensure we can re-read if necessary
485486
return rePos;
486487
}

src/test/java/org/apache/commons/io/input/TailerTest.java

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,13 @@
1616
*/
1717
package org.apache.commons.io.input;
1818

19+
import java.io.BufferedReader;
1920
import java.io.File;
21+
import java.io.FileInputStream;
2022
import java.io.FileNotFoundException;
2123
import java.io.FileWriter;
2224
import java.io.IOException;
25+
import java.io.InputStreamReader;
2326
import java.io.RandomAccessFile;
2427
import java.io.Writer;
2528
import java.util.ArrayList;
@@ -105,6 +108,42 @@ public void testBufferBreak() throws Exception {
105108
listener.clear();
106109
}
107110

111+
public void testMultiByteBreak() throws Exception {
112+
final long delay = 50;
113+
final File origin = new File(this.getClass().getResource("/test-file-utf8.bin").toURI());
114+
final File file = new File(getTestDirectory(), "testMultiByteBreak.txt");
115+
createFile(file, 0);
116+
final TestTailerListener listener = new TestTailerListener();
117+
final String osname = System.getProperty("os.name");
118+
final boolean isWindows = osname.startsWith("Windows");
119+
tailer = new Tailer(file, listener, delay, false, isWindows);
120+
final Thread thread = new Thread(tailer);
121+
thread.start();
122+
123+
124+
BufferedReader reader = null;
125+
try{
126+
List<String> lines = new ArrayList<String>();
127+
reader = new BufferedReader(new InputStreamReader(new FileInputStream(origin)));
128+
String line = null;
129+
while((line = reader.readLine()) != null){
130+
write(file, line);
131+
lines.add(line);
132+
}
133+
134+
final long testDelayMillis = delay * 10;
135+
Thread.sleep(testDelayMillis);
136+
List<String> tailerlines = listener.getLines();
137+
assertEquals("line count",lines.size(),tailerlines.size());
138+
for(int i = 0,len = lines.size();i<len;i++){
139+
assertEquals("line "+i, lines.get(i), tailerlines.get(i));
140+
}
141+
}finally{
142+
tailer.stop();
143+
IOUtils.closeQuietly(reader);
144+
}
145+
}
146+
108147
public void testTailerEof() throws Exception {
109148
// Create & start the Tailer
110149
final long delay = 50;

0 commit comments

Comments
 (0)