common.io 是一個實用程序庫,協助開發IO功能。
org.apache.comons.io.input 包針對SUN JDK IO包進行了擴展,實現了一些功能簡單的IO類,主要包括了對字節/字符輸入流接口的實現
在項目開發中(斯凱閃電狗-日誌監控分析系統),出現了輸出中文亂碼的問題。具體跟蹤到org.apache.comons.io.input.Tailer類中。
原因:通過把byte轉化成char,然後由char變成String會造成中文亂碼。(如果直接將byte轉化成String,則不亂碼)
private long readLines(RandomAccessFile reader) throws IOException {
StringBuilder sb = new StringBuilder();
long pos = reader.getFilePointer();
long rePos = pos; // position to re-read
int num;
boolean seenCR = false;
while (run && ((num = reader.read(inbuf)) != -1)) {
for (int i = 0; i < num; i++) {
byte ch = inbuf[i];
switch (ch) {
case '\n':
seenCR = false; // swallow CR before LF
listener.handle(sb.toString());
sb.setLength(0);
rePos = pos + i + 1;
break;
case '\r':
if (seenCR) {
sb.append('\r');
}
seenCR = true;
break;
default:
if (seenCR) {
seenCR = false; // swallow final CR
listener.handle(sb.toString());
sb.setLength(0);
rePos = pos + i + 1;
}
sb.append((char) ch); // add character, not its ascii value
}
}
pos = reader.getFilePointer();
}
reader.seek(rePos); // Ensure we can re-read if necessary
return rePos;
}
修改方法:通過byteBuffer來收集所有的byte,然後轉化成String,則不會亂碼。
修改爲:
private long readLines(RandomAccessFile reader) throws IOException {
StringBuilder sb = new StringBuilder();
long pos = reader.getFilePointer();
long rePos = pos; // position to re-read
int num;
boolean seenCR = false;
ByteBuffer buffer = ByteBuffer.allocate(1024);
while (run && ((num = reader.read(inbuf)) != -1)) {
for (int i = 0; i < num; i++) {
byte ch = inbuf[i];
switch (ch) {
case '\n':
seenCR = false; // swallow CR before LF
<span style="color:#FF0000;">//listener.handle(sb.toString());</span>
<span style="color:#FF0000;">buffer.flip();
listener.handle(byteBufferToString(buffer));
buffer.clear();</span>
sb.setLength(0);
rePos = pos + i + 1;
break;
case '\r':
if (seenCR) {
sb.append('\r');
<span style="color:#FF0000;">buffer.put(new byte[] { '\r' });</span>
}
seenCR = true;
break;
default:
if (seenCR) {
seenCR = false; // swallow final CR
<span style="color:#FF0000;">//listener.handle(sb.toString());</span>
<span style="color:#FF0000;">buffer.flip();
listener.handle(byteBufferToString(buffer));
buffer.clear();</span>
sb.setLength(0);
rePos = pos + i + 1;
}
sb.append((char) ch); // add character, not its ascii value
<span style="color:#FF0000;">try{
buffer.put(ch); //如果爲空,可能出現NIO的一個異常
}catch(Exception e){
logger.error("向buffer中插入數據出錯",e);
}</span>
}
}
pos = reader.getFilePointer();
}
reader.seek(rePos); // Ensure we can re-read if necessary
return rePos;
}
<span style="color:#FF0000;"></span>
byteBuffer轉化成String的方法:
<span style="color:#FF0000;">private static String byteBufferToString(ByteBuffer buffer) {
CharBuffer charBuffer = null;
try {
Charset charset = Charset.forName("UTF-8");
CharsetDecoder decoder = charset.newDecoder();
charBuffer = decoder.decode(buffer);
buffer.flip();
String result = charBuffer.toString();
return result;
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}</span>