hadoop 中 的Text類與java中的String類感覺上用法是相似的,但兩者在編碼格式和訪問方式上還是有些差別的,要說明這個問題,首先得了解幾個概念;
字符集: 是一個系統支持的所有抽象字符的集合。字符是各種文字和符號的總稱,包括各國家文字、標點符號、圖形符號、數字等。例如 unicode就是一個字符集,它的目標是涵蓋世界上所有國家的文字和符號;
字符編碼:是一套法則,使用該法則能夠對自然語言的字符的一個集合(如字母表或音節表),與其他東西的一個集合(如號碼或電脈沖)進行配對。即在符號集合與數字系統之間建立對應關系,它是信息處理的一項基本技術。通常人們用符號集合(一般情況下就是文字)來表達信息。而以計算機為基礎的信息處理系統則是利用元件(硬件)不同狀態的組合來存儲和處理信息的。元件不同狀態的組合能代表數字系統的數字,因此字符編碼就是將符號轉換為計算機可以接受的數字系統的數,稱為數字代碼。
字符編碼與字符集通常是一一對應的關系,例如utf-8,utf-16,utf-32都是unicode的不同編碼格式;
utf-8: 將unicode字符集分成1~4個字節的形式表示
utf-16: 將unicode中編號從1到65536的字符都用兩個字節表示(因為前65536個被認為是常用字符),大於65536的字符通過變換的方法變成4個字節來存儲;
utf-8 與 utf-16具體的編碼變換方法,大家感興趣的話可以從網上搜索來看;
Hadoop中的Text類為了與外界更好的交互,采用的是utf-8的編碼,而java的char,String,StringBuffer則默認使用的是utf-16編碼;兩者在使用和訪問的時候其實是有一些差別的。
這里借用了網上一篇博客中的例子 : http://blog.csdn.net/lastsweetop/article/details/9249411 來說明Text類與String類在訪問上的區別
第一個行表示unicode字符集中的序號(也是以16進制表示),第二行表示的是采用utf-8編碼的情況,第三行表示的是用utf-16編碼的情況,可以看到,第四個字符在utf-16編碼下也占用4個字節(兩個char單元,每個char單元是兩字字節);
代碼如下,下面會分別解釋結果中每一行的意思;
String str = "\u0041\u00DF\u6771\uD801\uDC00";
Text text = new Text("\u0041\u00DF\u6771\uD801\uDC00");
System.out.println(str.length());
System.out.println(str.getBytes("UTF-8").length);
System.out.println(str.indexOf("\u0041"));
System.out.println(str.indexOf("\u00DF"));
System.out.println(str.indexOf("\u6771"));
System.out.println(str.indexOf("\uD801\uDC00"));
System.out.println(str.charAt(0)=='\u0041');
System.out.println(str.charAt(1)=='\u00DF');
System.out.println(str.charAt(2)=='\u6771');
System.out.println(str.charAt(3)=='\uD801');
System.out.println(str.charAt(4)=='\uDC00');
System.out.println(str.codePointAt(0));
System.out.println(str.codePointAt(1));
System.out.println(str.codePointAt(2));
System.out.println(str.codePointAt(3));
System.out.println(text.getLength());
System.out.println(text.find("\u0041"));
System.out.println(text.find("\u00DF"));
System.out.println(text.find("\u6771"));
System.out.println(text.find("\uD801\uDC00"));
System.out.println(text.charAt(0));
System.out.println(text.charAt(1));
System.out.println(text.charAt(3));
System.out.println(text.charAt(6));
5 //String 中的getLength表示的是字符串中char單元的個數,如果String中包含4個字節(兩個char單元)表示的字符,像上文中的第四個字符,getLength也是統計的是char 的數量,此時getLength的結果與實際的字符數是不同的。
10 //getBytes() 方法返回根據相應編碼(此例為utf-8)編碼后的字節數;四個字符按utf-8編碼后的字節數分別為1、2、3、4,所以總的字節數是10
0 //String 的indexOf方法返回的字符出現的位置;
1
2
3
true //String的charAt方法,返回的是相應位置的char編碼單元
true
true
true
true
65 //String類的codePointAt()方法返回的是對應位置的unicode字符集序號,即上文u+0041的十進制表示;
223 //
26481
66560 //這里要特別強調一下,由於第四個字符占據了兩個char單元,codePointAt()方法會進行相應的判斷,如果發現之后一位的char單元與當前位置的char單元是從屬於一個 unicode字符的話,就將兩者和在一起;如果不是的話,就單獨輸出當前的char單元;
10 //Text 類的getLength方法返回的是utf-8編碼之后的字節數
0 //Text類的find方法也是按照字節數的偏移位置來的
1
3
6
65 //Text類的charAt方法也是返回對應的unicode字符集序號;
223
26481
66560 //如果這一句換成 charAt(5) 那么返回的是 -1
由於Text的特點決定了:對Text的遍歷會麻煩一些,需要變成bytes后通過bytesToCodePoint()方法進行訪問;
ByteBuffer buffer = ByteBuffer.wrap(text.getBytes(), 0, text.getLength());
int cp;
while (buffer.hasRemaining() && (cp = Text.bytesToCodePoint(buffer)) != -1) {
System.out.println(Integer.toHexString(cp) + "haha");
}
輸出結果為:
41
df
6771
10400