编程过程中偶尔会遇到乱码问题,对字符编码进行一定的理解可以加快解决问题的速度.
基本概念
字符集
:系统支持的所有抽象字符的集合。常见字符集
:ASCII、ISO-8859-1、GB2312、GBK、GB18030、BIG5、Unicode等。编码
(encoding): 编码是信息从一种形式或格式转换
为另一种形式的过程。解码,是编码的逆过程
。字符编码
(character encoding): 把字符集中的字符编码为指定集合中某一对象(例如:比特模式、自然数序列、8位元组或者电脉冲),以便文本在计算机中存储和通过通信网络的传递。一般一种字符集对应一种字符编码方式,其中Unicode字符集有多种编码方式,比如UTF-8、UTF-16、UTF-32。不同字符集间转换一般使用Unicode字符集作为中介,先转换为Unicode字符,然后再查码表进行转换。
Unicode
Unicode (万国码,国际码,统一码,单一码)是计算机领域的一项业界标准,对世界上大部分文字系统进行整理和编码,使电脑可以用更为简单的方式类呈现和处理文字.
- Java程序在运行时,内存中的字符使用Unicode字符集,使用UTF-16的编码方式(一般为2个字节,辅助平面字符需要4个字节)
- Unicode使用16位的编码空间,每个字符占用2个字节(附加字符需要4个字节)
- 一个字符的Unicode编码是确定的
- Unicode的实现方式称为Unicode转换格式(Unicode Transformation Format,简称为UTF).
UTF-8
UTF-8(8-bit Unicode Transformation Format)是一种针对Unicode的可变长度字元编码,也是一种前缀码。它可以用来表示Unicode标准中的任何字元,且其编码中的第一个位元组仍与ASCII相容,这使得原来处理ASCII字元的软体无须或只须做少部份修改,即可继续使用。因此,它逐渐成为电子邮件、网页及其他储存或传送文字的应用中,
优先采用
的编码。
- 只包含7位ASCII字符的文件在ASCII和UTF-8两种编码方式下是一樣的
- UTF-8是一种变长编码方式(1-4个字节),兼容ASCII
- 其中英文字符占用1个字节,中文字符占用3个字节,所以相对来说,占用存储空间较少
UTF-16
- 采用2个字节或者4个字节(辅助平面字符)的编码方式,是Java中字符的编码方式
- 英文也占用2个字节,所以比较浪费空间
- 优点是编解码方便,效率高,字符定位容易
- 缺点是占用空间大,采用顺序编码,若字符损坏无法进行校验
UTF-32
- 采用4个字节的定长编码方式
- 英文也占用4个字节
- 占用空间大
- 有大小端的区别
Java中的编码
- Java程序默认使用UTF-16编码(字符串
String
的编码) - JVM编码:Uninx默认使用UTF-8,Windows默认使用GBK(文件系统编码方式),所以最好指定编码方式,加入JVM参数
-Dfile.encoding=utf8
- String的getBytes()方法默认使用的是JVM默认的编码方式来编码(不同操作系统可能会不一样,所以最好指定编码方式)
- String的getBytes(Charset)方法指定编码方式来编码字符串
- new String(byte[])方法默认使用的是JVM默认的编码方式来解码(不同操作系统可能会不一样,所以最好指定编码方式)
- new String(byte[],Charset)方法可以对byte[]进行指定编码方式解码
- 乱码需要使用当时编码时候用的
错误解码方式
进行编码后再重新解码 - 很多框架使用
ISO-8859-1
编码,存在黑洞问题,容易造成中文丢失,new String(str.getBytes("utf-8"),"iso-8859-1");
有可能能解决问题
不同编码方式占用字节(byte)
非特殊字符情况下
编码方式 | 1个英文字符(ASCII) | 1个中文字符 |
---|---|---|
GB2312 | 1 | 2 |
GBK | 1 | 2 |
UTF-8 | 1 | 3 |
UTF-16 | 2 | 2 |
UTF-32 | 4 | 4 |
Unicode | 2 | 2 |
其中GBK兼容GB2312,可以说GBK是GB2312的超集