java中InputStream、OutputStream讀取以字節爲單位,而Reader、Writer以字符爲讀寫單位。下面例子模仿Reader直接讀取utf-8格式編碼字符:java
public class Utf8Reader { private InputStream inputStream; //10000000取反 private static int back10head=127; //11000000取反 private static int back110head= 191; //11100000取反 private static int back1110head= 223; //3個字節表示字符 byte[] threeBytes = new byte[3]; //2個字節表示字符 byte[] twoBytes = new byte[2]; public Utf8Reader(InputStream inputStream){ this.inputStream=inputStream; } /** * 讀取一個字符 * @return * @throws IOException */ public int readChar() throws IOException{ //讀取一個字節 int read = inputStream.read(); //字節以1110開頭,表明用3個字節表示一個字符 if(read>=224){ threeBytes[0]=(byte) read; //讀取接下來的兩個字節 inputStream.read(threeBytes, 1, 2); //將3個字節轉化爲字符 return parseThreeByte(threeBytes); //字節以110開頭,即是用2個字節表示一個字符 }else if(read>=192){ twoBytes[0]=(byte) read; //讀取接下來的一個季節 inputStream.read(twoBytes, 1, 1); //將兩個字節轉化爲字符 return parseTwoByte(twoBytes); //字節以10開頭,只能做爲多字節字符中的一個字節,不能做爲頭部 }else if(read>=128){ throw new IOException("非法編碼["+read+"]字符以10開頭"); //ASCII碼或文件結束符-1,直接返回 }else if(read>=0){ return read; }else{ return -1; } } /** * 將2個字節轉化爲1個字符 * 將110xxxxx 10xxxxxx 字節數值轉化爲 xxxx xxxxxx 字符 * @param twoBytes2 * @return */ private int parseTwoByte(byte[] bytes) { //去掉二字節頭部表示 int head=bytes[0]&back110head; //向右移6位 head=head<<6; //去掉組成部分頭部表示 int tail=bytes[1]&back10head; return (char) (head|tail); } /** * 將三個字節轉化爲1個字符 * 將1110xxxx 10xxxxxx 10xxxxxx字節數值轉化爲 xxx xxxxxx xxxxxx字符 * @param threeBytes2 * @return */ private int parseThreeByte(byte[] bytes) { //去掉三字節頭部表示 int head=bytes[0]&back1110head; //向右移12位 head=head<<12; //去掉組成部分頭部表示 int second=bytes[1]&back10head; int third=bytes[2]&back10head; //第二個字符向右移6位 second=second<<6; return head|second|third; } }