您的位置:首页 > 职场人生

黑马程序员java基础篇----字符编码

2013-04-07 17:53 246 查看
android培训java培训期待与您交流

一、编码解码&码表

1、常见的编码表:

   ASCII:美国标准信息交换码---用一个字节的7位可以表示。

   ISO8859-1:拉丁码表---欧洲码表用一个字节的8位表示,负数。

   GB2312:中国的中文编码表---每个文字用两个字节表示,两个都是负数,且该码表兼容ASCII码表。

   GBK:中国的中文编码表升级,融合了更多的中文文字符号---同上。

   Unicode:国际标准码,融合了多种文字---所有文字都用两个字节来表示,Java语言使用的就是unicode

   UTF-8:根据投标来确定是用一个、两个还是三个字节来表示一个字符。

2、编码与解码:

   编码    字符串---->字节数组

   解码    字节数组---->字符串

二、转换流与码表的融合

1、InputStreamReader:字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。

   OutputStreamWriter:字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。

2、转换流工作原理:

public class TransitionStreamDemo {
public static void main(String[] args){
OutputStreamWriter iswUtf = null;
InputStreamReader isrUtf = null;
try {
//编码码表指定为utf-8
iswUtf = new OutputStreamWriter(new FileOutputStream("utf.txt"), "utf-8");
iswUtf.write("你好");
} catch (Exception e) {
throw new RuntimeException("文件创建异常");
}finally{
try {
if (iswUtf != null)
iswUtf.close();
} catch (Exception e2) {
throw new RuntimeException("关闭输出流异常");
}
}
char[] buf = new char[3];
int len = 0;
try {
//解码码表指定为utf-8
isrUtf = new InputStreamReader(new FileInputStream("utf.txt"), "utf-8");
len = isrUtf.read(buf);
System.out.println(new String(buf, 0, len));
} catch (Exception e) {
throw new RuntimeException("文件读取异常");
}finally{
try {
if (isrUtf != null)
isrUtf.close();
} catch (Exception e2) {
throw new RuntimeException("关闭输入流异常");
}
}
}
}

程序执行流程按下图①-⑤所示的顺序进行:



 三、乱码异常分析

1、UTF-8&GBK相关异常

public class CodingEncoding {
public static void main(String[] args) throws IOException {

OutputStreamWriter iswUtf =			//指定编码码表为utf-8
new OutputStreamWriter(new FileOutputStream("utf.txt"),"utf-8");
OutputStreamWriter iswGbk =			//指定编码码表为gbk
new OutputStreamWriter(new FileOutputStream("gbk.txt"),"gbk");

iswUtf.write("你好");
iswUtf.close();

iswGbk.write("你好");
iswGbk.close();

char[] buf = new char[3];
int len = 0;

InputStreamReader isrUtf =	//编码时指定码表为utf-8,解码时指定码表为gbk
new InputStreamReader(new FileInputStream("utf.txt"),"gbk");
InputStreamReader isrGbk =	//编码时指定码表为gbk,解码时指定码表为utf-8
new InputStreamReader(new FileInputStream("gbk.txt"),"utf-8");

len = isrUtf.read(buf);
isrUtf.close();
System.out.println(new String(buf,0,len));

len = isrGbk.read(buf);
isrGbk.close();
System.out.println(new String(buf,0,len));

}
}

本程序运行结果如下:


    

这种情况的其实就是编码码表与解码码表的不一致性引起的,而且这中间也是有规律可循的,一般若编码时指定码表为

utf-8,解码时指定码表为gbk,那么解码会出现汉字或其他乱码而不是?,如果反过来的情况一般大部分都是问号,具体

原理看下图:



 2、ISO8859-1相关异常及解决办法

public class StringCoding {

public static void main(String[] args) throws Exception{
String str = "你好";
//使用GBK字符集来对字符串进行编码
byte[] GBKByte = str.getBytes("GBK");
System.out.println(Arrays.toString(GBKByte));//打印结果:[-60, -29, -70, -61]

String ISOString = new String(GBKByte,"ISO8859-1");
System.out.println(ISOString);//打印结果:全是?,且个数为4

//使用ISO8859-1字符集进行重新编码
byte[] ISOByte = ISOString.getBytes("ISO8859-1");
System.out.println(Arrays.toString(ISOByte));//打印结果:[-60, -29, -70, -61]

//使用GBK字符集解码
String GBKString = new String(ISOByte,"GBK");
System.out.println(GBKString);//打印结果:你好
}
}

本程序的基本原理如下图



3、修改版UTF-8注意点

   首先看一下修改版的编码规则:



修改版UTF-8在进行编码时,会参考表示头信息进行字节数的控制,就像上图所示,当读取到一个字节的首位为0,则这个字节单独表示一个字符;当读取的字节以110开头,如果是就以两个字节表示一个字符,且第二个字符一10开头;同理,当读取的字节以1110开头时,就会用三个字节表示一个字符,且后两个字节都是以10开头。一个很特殊的案例就是"联想"用GBK编码以后的字节码为"11000001","10101010","11001101","10101000"这四个字节正好符合修改版UTF-8中用两个字节表示一个字符的规则,所以当当用记事本来保存"联想"以后再打开时,记事本就会查找修改版UTF-8的码表进行解码,所以会出现乱码。

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: