第7讲 IO/输入与输出-字符编码

字符编码
·计算机里只有数字,计算机软件里面的一切都是用数字表示的,屏幕上显示的一个个的字符也不例外。
·字符a对应的数字97,字符b对应的数字98等,这种字符与数字对应的编码规则被称为ASCII(美国标准信息交换码)。ASCII的最高bit位都为0,也就是说这些数字都在0到127之间。
·中国大陆将每一个中文字符都用两个字节的数字来表示,中文字符的每个字节的最高位bit都是1,中国大陆为每个中文字符制定的编码规则称为:GB2312(国际码)
·在GB2312的基础上,对更多的中文字符(包括繁体)进行了编码,新的编码规则称为GBK。
·在中国大陆使用的计算机系统上,GBK和GB2312就被称为该系统的本地字符集。
·“中国”的“中”字,在中国大陆的编码是十六进制的D6D0,而在中国台湾的编码是十六进制的A4A4A,台湾地区对中文字符集的编码规则称为BIG5(大五码)。
·在一个国家的本地化系统中出现的一个字符,通过电子邮件传送到另外一个国建的本地化系统中,看到的就不是那个原始字符了,而是另外那个国家的一个字符或乱码。

Unicode编码
·ISO(国际标准化组织)将全世界所有的符号进行了统一编码,称之为Unicode编码。
·“中”这个符号,在全世界的任何角落始终对应的都是一个十六进制的数字4e2d。
·如果所有的计算机系统那个都使用Unicode编码,在中国大陆的本地化系统中显示的“中”这个符号,发送到伊拉克的本地化系统中,显示的仍然是“中”这个符号。
·Unicode编码的字符都占用了两个字节的大小,对应ASCII码所表示的字符,只是简单地在ASCII码原来占用的一个字节前面,增加一个所有bit为0的字节。
·Unicode只占用两个字节,在全世界范围内所表示的字符个数不会超过2的16次方(65536),实际上,Unicode编码中海保留了两千多个数值没用用于字符编码。
·在相当长的一段时间期内,本地化字符编码将与Unicode编码共存。
·Java中的字符使用的都是Unicode编码,Java在通过Unicode保证跨平台特性的前提下,也支持本地平台字符集。

UTF-8编码(UTF-16)
ASCII码字符保持原样,仍然只占用一个字节,对于其它国家的字符,UTF-8使用两个或者三个字节来表示。使用UTF-8编码的文件,通常都要用EF BB BF作为文件开头的三个字节数据。

字符的UTF-8编码与Unicode编码之间的转换关系对应下列规则:
 -/u0001和/u007f之间的字符,UTF-8编码为:(byte)c。
 -/u0000或其范围在/u0080和/u07ff之间的字符,UTF-8编码为:
    (byte)(0xc0|(0x1f&(c>>6))),(byte)(0x80|(0x3f&c))。
 -/u0800和/ufff之间的字符,UTF-8编码为:(byte)(0xe0|(0x0f&(c>>12))),
  (byte)(0x80|(0x3f&(c>>6))),(byte)(0x80|(0x3f*c))
UTF-8的优点:
 ·不出现内容为0x00字节
 ·便于应用程序检测数据在传输过程中是否发生了错误
 ·直接处理使用ASCII码的英文文档
UTF-8的缺点:唯一缺点是有些字符需使用三个字节来表示,这就比Unicode编码多了1.5倍,特别是在表示中、日、韩等过的文字的时候表现的就更多了。

UTF-16编码
·UTF-16编码在Unicode基础上进行了一些细节上的扩充,增加了对Unicode编码没有包括的那些字符的表示。
·UTF-16对Unicode的扩充并没有影响Unicode编码所包括的那些字符,只是增加了对Unicode编码没有包括的那些字符的表示方式,一个使用Unicode编码的字符就是UTF-16格式的。
·Unicode编码将0xD800-0xDFFF区间的数值保留出来,UTF-16扩充的字符,占用四个字节,前面两个字节的数值为0xD800-0xD8FF之间,后面两个字节的数值为0xDC00-0xDFFF之间。
·为什么不让前面和后面的两个字节的数值都位于0xD800-0xDFFF之间呢?
·在不同的体系结构的计算机系统中,UTF-16编码的Unicode字符在内存中的字节存储顺序是不同的。
·对于0x1234这样一个双字节数据,使用LittleEndian和Big-Endian两种方式在内存中存储的格式:
·如果文件以0xFE 0xFF这两个字节开头,则表明文版的其余部分是Big-Endian的UTF-16编码;如果文件以0xFF 0xFE这两个字节开头,则表明文版的其余部分是Little-Endian的UTF-16编码。

字符编码的操作体验
·查看中文字符的GB2312码
·查看中文字符的UTF-8码
·查看中文字符的Unicode码
·在Windows记事本程序中用不同的编码格式存储文本文件

字符编码应用的一个奇怪的现象
·用Windows记事本程序创建三个文件,其中分别输入"联通"、"联想"、"联",然后打开这三个文件,内容为"联通"和"联"的文件显示异常。
了解即可。

字符编码的编程体验
·打印中文字符的Unicode码
·打印中文字符的GB2312码
·验证写入到屏幕输出流的中文字符所采用的编码
 public static void main(String[] args) throws Exception {
  // TODO: Add your code here
  String strChina = "中国";
  System.out.println ("开始打印Unicode编码:");
  for(int i=0;i<strChina.length();i++)
  {
   System.out.println (Integer.toHexString((int)strChina.charAt(i)));
  }
  byte[] buf = strChina.getBytes("gb2312");
  System.out.println ("开始打印GB2312编码:");
  for(int i=0;i<buf.length;i++)
  {
   
   System.out.println(Integer.toHexString((int)buf[i]));
  }
  System.out.println ("开始打印屏幕输出流的中文字符所采用的编码:");
  for(int i=0;i<buf.length;i++){
   
   System.out.write(buf[i]);
  }
  System.out.println ("/n中国");
 }

从这个例子中我们可以看出,System.out.println ("/n中国");方法实际上自动帮忙我执行了两部操作:
1.byte[] buf = "/n中国".getBytes("gb2312");系统调用默认的字符集编码了字符串“中国”
2.for(int i=0;i<buf.length;i++){System.out.write(buf[i]);}然后,系统将这个编码后的byte数组写入到屏幕输出流中,屏幕上就显示了我们看到的中国。
注意:在这个地方我们调用System.out.write(buf[i]);将字节数组写入到屏幕输出流中的时候并没有刷新流,我们可以使用System.out.println()或者System.out.flush()方法来刷新流。
System.out对象是PrintStream类型的,其中的方法也是类PrintStream中的方法。
·查看系统的缺省编码
System.getProperties().list(System.out);
·修改系统的缺省编码
System.setProperty("file.encoding","iso8859-1");
·验证从键盘输入流中读取的中文字符所采用的编码
从键盘输入流进来的数据,经过系统安装默认的字符集解码成的字符串,再次输出到屏幕的时候,如果解码和编码使用的不同的字符集则可能会导致显示乱码,解决的办法是再次用解码的时候字符集编码
字符串得到原始的字节数据,然后再按照屏幕显示所需要的字符集编码写入屏幕输出流中去显示。
System.out.println(new String(str.getBytes("iso8859-1"),"GB2312"));
要注意的是,这个地方原始键盘输入的字符是安装iso8859-1码的形式解码称为java中的字符即Unicode码,
这个时候我们逆向再编码回字节数据时不会丢失信息的,而反过来可能丢失数据,也就是说这种编码解码时不可逆的。
下面的例子可以说明这种信息的丢失:
  String str = "中国";
  byte[] buf = str.getBytes("iso8859-1");
  System.out.println(buf.length);
  String decodeStr = new String(buf,"iso8859-1");
  System.out.println (decodeStr);
执行结果:
2
?? 
在Java中字符采用的Unicode码,将一个Unicode码的字符串转换成一个有指定字符集的字节码的过程叫做编码,反之叫解码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值