common.io中Tailer類讀取文件內容亂碼問題解決

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>


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章