设为首页 收藏本站
查看: 1240|回复: 0

[经验分享] Hadoop中Writable类之二

[复制链接]

尚未签到

发表于 2015-7-12 08:43:25 | 显示全部楼层 |阅读模式
  1.ASCII、Unicode、UFT-8
  在看Text类型的时候,里面出现了上面三种编码,先看看这三种编码:
  ASCII是基于拉丁字母的一套电脑编码系统。它主要用于显示现代英语和其他西欧语言。它是现今最通用的单字节编码系统,并等同于国际标准ISO/IEC 646。ASCII是7位字符集,是美国标准信息交换代码的缩写,为美国英语通信所设计。它由128个字符组成,包括大小写字母、数字0-9、标点符号、非打印字符(换行副、制表符等4个)以及控制字符(退格、响铃等)组成。从定义,很明显,单字节编码,现代英语,局限性很大。
  由于它是针对英语设计的,当处理带有音标符号的亚洲文字就会出现问题。因此,创建除了一些包含255个字符的由ASCII扩展的字符集。其中有两种比较有名:IBM字符集和ISOLatin-1,但是,仅仅汉语字母表就有80000以上个字符。但是把汉语、日语、越南语的一些相似的字符结合起来,在不同的语言里,使用不同的字符代表不同的字,这样,只用2个字节就可以编码地球上几乎所有的文字。因此UNICODE编码由此创建。
  Unicode(统一码、万国码、单一码)是一种在计算机上使用的字符编码。Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。和AASCII不同,它共过增加一个 高字节对ISO Latin-1字符集进行扩展,当着写高字节为0时,低字节就是ISO Latin-1字符。
  但是,对可以使用ASCII表示的字符使用UNICODE来表示,并不是很高效,因为UNICODE是两个字节组成的,而ASCII是由单字节组成的。UNICODE比ASCII占用大了一倍的空间。为了解决这个问题,就出现了一些中间格式的字符集,他们被称为通用转换格式,即UTF。常见的UTF格式有:UTF-7、UTF-7.5、UTF-8等。
  UTF-8(8-bit Unicode Transformation Format)是一种针对Unicode的可变长度字符编码,又称万国码。由Ken Thompson于1992年创建。现在已经标准化为RFC 3629。UTF-8用1到6个字节编码UNICODE字符。用在网页上可以同一页面显示中文简体繁体及其它语言(如英文,日文,韩文)。UTF-8转换表表示如下:
DSC0000.png
  
  实际表示ASCII字符的UNICODE字符,将会编码成1个字节。并且UTF-8表示会与ASCII字符表示是一样的。所有其他的UNICODE字符转化成UTF-8将需要至少2个字节。


优点:

UTF-8编码可以通过屏蔽位和移位操作快速读写。字符串比较时strcmp()和wcscmp()的返回结果相同,因此使排序变得更加容易。字节FF和FE在UTF-8编码中永远不会出现,因此他们可以用来表明UTF-16或UTF-32文本(见BOM) UTF-8 是字节顺序无关的。它的字节顺序在所有系统中都是一样的,因此它实际上并不需要BOM。

缺点:

你无法从UNICODE字符数判断出UTF-8文本的字节数,因为UTF-8是一种变长编码它需要用2个字节编码那些用扩展ASCII字符集只需1个字节的字符 ISO Latin-1 是UNICODE的子集, 但不是UTF-8的子集 8位字符的UTF-8编码会被email网关过滤,因为internet信息最初设计为7位ASCII码。因此产生了UTF-7编码。 UTF-8 在它的表示中使用值100xxxxx的几率超过50%, 而现存的实现如ISO 2022, 4873, 6429, 和8859系统,会把它错认为是C1 控制码。因此产生了UTF-7.5编码。



Java的字符类型采用的是UTF-16编码方式对Unicode编码表进行表示。其中一个char类型固定2Bytes(16bits)。

UTF-16是Unicode字符编码五层次模型的第三层:字符编码表(Character Encoding Form,也称为 "storage format")的一种实现方式。即把Unicode字符集的抽象码位映射为16位长的整数(即码元)的序列,用于数据存储或传递。Unicode字符的码位,需要1个或者2个16位长的码元来表示,因此这是一个变长表示。  2.Text类型
  Text简介
  Text是针对UTF-8序列的Writable类。一般可以认为等价于java.lang.String的Writable。
  由于它着重使用标准的UTF-8编码,因此Text类的索引是根据编码后字节序列中的位置实现的。并非字符串中的Unicode字符,也不是Java Char的编码单元。对于ASCII字符串,这三个索引位置的概念是一致的。
  String 和 Text区别
  上面已经提到了,Text类的索引是根据编码后字节序列中的位置实现的。String的索引是Java Char编码单元实现的。当字符串为ASCII码的时候,也就是全部为7位的单字节的时候,String 和 Text一致!
  (1).当字符串为ASCII码(单字节)
  Example:



1 package cn.roboson.writable;
2
3 import java.io.UnsupportedEncodingException;
4
5 import org.apache.hadoop.io.Text;
6
7 /**
8  * 1.区别Text和String
9  * 2.首先从ASSCII字符串比较(也就是全部都是7位单字节),
10  * 3.通过getLength()、getBytes()、charAt()、find()、indexof()、codePointAt()方法来测试
11  * @author roboson
12  *
13  */
14 public class WritableText01 {
15     
16     public static void main(String[] args) throws UnsupportedEncodingException {
17         //Hadoop中全部都是7位单字节(H,a,d,o,o,p)
18         String str = new String("Hadoop");
19         Text t = new Text("Hadoop");
20         
21         //“Hadoop”的长度,也就是所含char编码单元的个数(H,a,d,o,o,p)共6个
22         System.out.println("String length:"+str.length());     //6
23         
24         //String的getBytes() 方法返回根据相应编码(此例为utf-8)编码后的字节数,因为Hadoop这个字符串都是单字节的,所以,用utf-8编码,效果同ASCII编码一样,都是6个字节
25         System.out.println("String getBytes:"+str.getBytes("UTF-8").length);  //6
26         
27         //String的charAt()方法返回的是相应位置的char编码单元
28         System.out.println("String chartAt:"+str.charAt(0));   //H
29         System.out.println("String chartAt:"+str.charAt(5));   //p
30         
31         //String的indexOf()方法返回的字符出现的位置
32         System.out.println("String indexof:"+str.indexOf("H"));
33         System.out.println("String indexof:"+str.indexOf("p"));
34         
35         //String的codePointAt()方法返回的对应位置的unicode字符集序号
36         System.out.println("String codePointAt:"+str.codePointAt(0));  //72
37         System.out.println("String codePointAt:"+str.codePointAt(5));  //112
38         
39         //“Hadoop”的长度,也就是有UTF-8编码后所含有的字节数
40         System.out.println("Text length:"+t.getLength());     //6
41         
42         //同indexof()方法相似,返回字节出现的位置
43         System.out.println("Text find:"+t.find("H"));        //0
44         System.out.println("Text find:"+t.find("a"));        //1
45         
46         //Text类的charAt方法也是返回对应的unicode字符集序号
47         System.out.println("Text char:"+t.charAt(0));        //72
48         System.out.println("Text char:"+t.charAt(1));        //112
49     }
50 }
  
  运行结果:
DSC0001.png
  (2).当字符串为多个字节
  一旦使用多个字节来编码时,Text和String之间区别就很明显了
  

Unicode code pointU+0041U+00DFU+6771U+10400
UTF-8 code units41c3 9fe6 9d b1fo 90 90 80
Java representation\u0041\u00DF\u6771\uD801 \uDC00
  第一行表示unicode字符集中的序号(也是以16进制表示),第二行表示的是采用utf-8编码的情况,第三行表示的是用utf-16编码的情况,可以看到,第四个字符在utf-16编码下也占用4个字节(两个char单元,每个char单元是两字字节)
  分析:
  Text t = new Text("\u0041\u00DF\u6771\uD801\uDC00");
  Text中的长度是由编码后字节的个数所决定的!那么,字节的个数是如何算的呢?在上文的UTF-8转换表图中有说明:
  如下图,是t的字节数的实现,通过其二进制的位数,然后,同UTF-8转换表对比,从而得出其字节数!

unicode二进制位数字节数
U+0041100000171
U+00DF1101111182
U+6771110011101110001153
U+1040010000010000000000174
  
  t的长度:1+2+3+4=10;
  可以通过下面的例子来验证:
  Example:



1 package cn.roboson.writable;
2
3 import java.io.UnsupportedEncodingException;
4
5 import org.apache.hadoop.io.Text;
6
7 public class WtitableText {
8     public static void main(String[] args) throws UnsupportedEncodingException {
9         String str = "\u0041\u00DF\u6771\uD801\uDC00";
10
11         Text text = new Text("\u0041\u00DF\u6771\uD801\uDC00");
12
13         System.out.println(str.length());                         //5
14         
15         System.out.println(str.getBytes("UTF-8").length);         //10
16         String str1="\u0041";
17         System.out.println(str1.getBytes("UTF-8").length);         //1
18         String str2="\u00DF";
19         System.out.println(str2.getBytes("UTF-8").length);         //2
20         String str3="\u6771";
21         System.out.println(str3.getBytes("UTF-8").length);         //3
22         
23         String str4="\uD801\uDC00";
24         System.out.println(str4.getBytes("UTF-8").length);         //4
25         
26         System.out.println(str.indexOf("\u0041"));                //0
27         System.out.println(str.indexOf("\u00DF"));                //1
28         System.out.println(str.indexOf("\u6771"));                //2
29         System.out.println(str.indexOf("\uD801\uDC00"));          //3
30
31         System.out.println(str.charAt(0)=='\u0041');              //true
32         System.out.println(str.charAt(1)=='\u00DF');              //true
33         System.out.println(str.charAt(2)=='\u6771');              //true
34         System.out.println(str.charAt(3)=='\uD801');              //true
35         System.out.println(str.charAt(4)=='\uDC00');              //true
36
37         System.out.println(str.codePointAt(0));                   //65
38         System.out.println(str.codePointAt(1));                   //223
39         System.out.println(str.codePointAt(2));                   //26481
40         System.out.println(str.codePointAt(3));                   //66560
41
42
43         System.out.println(text.getLength());                     //10
44         System.out.println(text.find("\u0041"));                  //0
45         System.out.println(text.find("\u00DF"));                  //1
46         System.out.println(text.find("\u6771"));                  //3
47         System.out.println(text.find("\uD801\uDC00"));            //6
48
49         System.out.println(text.charAt(0));                       //65
50         System.out.println(text.charAt(1));                       //223
51         System.out.println(text.charAt(3));                       //26481
52         System.out.println(text.charAt(6));                       //66560
53     }
54 }
  
  运行结果:
   DSC0002.png
  3.Text类型的迭代
  通过上面,也知道,通过字节量进行位置索引来实现对Text类Unicode字符的迭代是非常复杂的,因为字节数变化很大(1~6),你不能简单地通过增加位置的索引值来实现。
  迭代的实现:
  将Text对象转换为Java.nio.ByteBuffer对象,然后利用缓冲去对Text对象反复调用bytesToCodePoint()静态方法。该方法能头获取下一代码的位置,并返回相应的int值,最后更新缓冲区中的位置。通过bytesToCodePoint()方法可以检测出字符串的末尾,并返回-1.
  Example:遍历Text对象中的字符



1 package cn.roboson.writable;
2
3 import java.nio.ByteBuffer;
4
5 import org.apache.hadoop.io.Text;
6
7 public class WritableText03 {
8     
9     public static void main(String[] args) {
10         Text t = new Text("\u0041\u00DF\u6771\uD801\uDC00");
11         ByteBuffer buf = ByteBuffer.wrap(t.getBytes(),0,t.getLength());
12         int cp;
13         while(buf.hasRemaining() && (cp = Text.bytesToCodePoint(buf))!=-1){
14             //以十六进制的无符号整数形式返回一个整数参数的字符串表示形式。
15             System.out.println(Integer.toHexString(cp));
16         }
17     }
18 }
  
  运行结果:
   DSC0003.png
  
  
  4.Text类型的易变性
  与String相比,Text的另一个区别在于它是可变的。可以通过调用其中一个set()方法来重用Text实例。
  在某些情况下,getBytes()方法返回的字节数组可能比getLength()函数返回的长度更长,因此,在调用getBytes()之前,始终调用getLength()方法,因为,可能由此知道字节数组的中有多少是有效的。至于原因,还没弄明白



1 package cn.roboson.writable;
2
3 import org.apache.hadoop.io.Text;
4
5 public class WritableText04 {
6     
7     public static void main(String[] args) {
8         Text t = new Text("Hadoop");
9         System.out.println("Hadoop的长度:"+t.getLength());
10         System.out.println("Hadoop的字节数组:"+t.getBytes().length);
11         
12         
13         t.set(new Text("robo"));
14         System.out.println("robo的长度:"+t.getLength());
15         System.out.println("robo的字节数组:"+t.getBytes().length);
16     }
17 }
  
  运行结果:
DSC0004.png
  set(String str);
  set(Text text);这两种的效果又不一样。
  Example:



1 package cn.roboson.writable;
2
3 import org.apache.hadoop.io.Text;
4
5 public class WritableText04 {
6     
7     public static void main(String[] args) {
8         Text t = new Text("Hadoop");
9         System.out.println("Hadoop的长度:"+t.getLength());
10         System.out.println("Hadoop的字节数组:"+t.getBytes().length);
11         
12         
13         t.set("robo");
14         System.out.println("robo的长度:"+t.getLength());
15         System.out.println("robo的字节数组:"+t.getBytes().length);
16     }
17 }
  
  运行结果:
DSC0005.png
  参考:
  http://baike.baidu.com/link?url=knrf3QgRtcjQBusr_kuXdR6lclC1AyquSOpojyV_UXQ-L8XBKymFLpZP8rk6QTZTXdT32cHgQaLlLDzkuUzDGK
  http://www.iyunv.com/yuhan-TB/p/3752725.html
  《Hadoop权威指南》

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-85654-1-1.html 上篇帖子: 在Hadoop中,从MapFile文件中读取指定键值的元素 下篇帖子: 吐槽下《Hadoop权威指南(第二版)》的翻译
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表