看了孙鑫老师的相关讲解后,总结一下。
首先看清楚几种常用的字符集编码(java语言是采用unicode字符集编码来表示字符与字符串的):
ASCII(American Standard Code for Information Interchange,美国信息互换标准代码),是基于常用的英文字符的一套电脑编码系统。我们知道英文中经常使用的字符、数字符号被计算机处理时都是以二进制码的形式出现的。这种二进制码的集合就是所谓的ASCII码。每一个ASCII码与一个8位(bit)二进制数对应。其最高位是0,相应的十进制数是0-127。如,数字“0”的编码用十进制数表示就是48。另有128个扩展的ASCII码,最高位都是1,由一些制表符和其它符号组成。ASCII是现今最通用的单字节编码系统。
GB2312:GB2312码是中华人民共和国国家汉字信息交换用编码,全称《信息交换用汉字编码字符集-基本集》。主要用于给每一个中文字符指定相应的数字,也就是进行编码。一个中文字符用两个字节的数字来表示,为了和ASCII码有所区别,将中文字符每一个字节的最高位置都用1来表示。
GBK:为了对更多的字符进行编码,国家又发布了新的编码系统GBK(GBK的K是“扩展”的汉语拼音第一个字母)。在新的编码系统里,除了完全兼容GB2312 外,还对繁体中文、一些不常用的汉字和许多符号进行了编码。
ISO-8859-1:是西方国家所使用的字符编码集,是一种单字节的字符集 ,而英文实际上只用了其中数字小于128的部分。
Unicode:这是一种通用的字符集,对所有语言的文字进行了统一编码,对每一个字符都用2个字节来表示,对于英文字符采取前面加“0”字节的策略实现等长兼容。如 “a” 的ASCII码为0x61,UNICODE就为0x00,0x61。
UTF-8:Eight-bit UCS Transformation Format,(UCS,Universal Character Set,通用字符集,UCS 是所有其他字符集标准的一个超集)。一个7位的ASCII码值,对应的UTF码是一个字节。如果字符是0x0000,或在0x0080与0x007f之间,对应的UTF码是两个字节,如果字符在0x0800与0xffff之间,对应的UTF码是三个字节。
我们运行java程序时,JVM有自己所支持的编码种类,用以下代码可以看到:
Set names = m.keySet();
Iterator it = names.iterator();
while (it.hasNext())
{
System.out.println(it.next());
}
然后可以通过以下代码看到我们目前JVM所使用的编码:
pps.list(System.out);
具体来说什么是编码,什么是解码?
在InputStreamReader JDK有这样描述:It reads bytes and decodes them into characters using a specified charset.(用指定的字符集将字节数组解码成字符串)。
相反OutputStreamWriter 描述:Characters written to it are encoded into bytes using a specified charset.(用指定的字符集将字符串编码成字节数组)。
理解这个以后一切好办了啦!
我们的OS一般是GBK编码的(凡是从磁盘上读取文件可以看成是用OS的字符集编码方式来对操作对象进行解码处理--从标准输入设备读取数据的时候是依赖OS的字符集)。而我们将从磁盘上文件经过处理得到我们想要的字符串等其它对象的时候,这一过程是用JVM的默认的字符集编码方式来处理的!由于不同的字符集编码方式有着不同的原理(前面所述),这样当编码与解码不一致的时候,自然而然就出现了可爱的乱码。
比如如下,将我们JVM字符集改成iso-8859-1这样在就与我们的OS不同:
当输入中文时自然就输出的是乱码了。
int data;
byte [] buf = new byte [ 100 ];
int i = 0 ;
while ((data = System.in.read()) != ' q ' )
{
buf[i] = ( byte )data;
i ++ ;
}
String str = new String(buf, 0 ,i);
System.out.println(str);
这时我们可以用string的一个构造方法:
String(byt[] bytes, String charsetName)
Constructs a new String by decoding the specified array of bytes using the specified charset.(用指定的字符集对字节数组进行解码)。
其中用到了string 的getBytes方法:
getBytes(String charsetName)
Encodes this String into a sequence of bytes using the named charset, storing the result into a new byte array.(用指定的字符集进行编码,将结果存放到一字节数组里面)重新构造一个string:
这样又可以重新得到我们想要的汉字了。
我们这例子中是GBK(OS)来编码的,然后采用iso-8859-1(JVM)来解码得到一个新string(此string是乱码),然后将此string用iso-8859-1重新编码,并且用指定的GBK来解码。得到一个新string(也就是strGBK),这个string就不再是乱码了。
但如果我们一开始就采用GBK解码得到的字符串,然后用ISO-8859-1编码,能否再解码回去得到我们的中文字符呢?显示不可以啦,因为用ISO-8859-1的编码的时候采用是一种单字节的字符集来对其编码,这样就丢失了一个字节(对中文来说)!所以这样是得不到中文字符的!