Skip to content

Latest commit

 

History

History
80 lines (59 loc) · 3.59 KB

22.编码解码.md

File metadata and controls

80 lines (59 loc) · 3.59 KB

#22.编码解码

未完成,误导自负 : )

##22.1 JVM中的编码

在JVM内部,字符串数据总是以unicode码的形式与JVM虚拟机交互,然而当字符串数据需要输出到系统外部时,例如输出到控制台,数据就会转为具体的编码格式进行输出。

System.out.println("中国");
  1. 无论文件以任何编码格式载入到JVM中,"中国"二字都会以unicode码的形式存在JVM中(\u4e2d\u56fd);
  2. 假如IDE控制台的编码为UTF-8,当对"中国"二字进行控制台输出时,系统会将unicode码转为具体的UTF-8编码格式。(\u4e2d\u56fd -> e4b8ade59bbd)
  "d6d0b9fa"  (GBK编码格式数据)
     ↓ 将数据已GBK格式转为Unicode码载入JVM中
  "\u4e2d\u56fd"  (数据的unicode码表示)
     ↓ 将unicode码转为UTF-8格式数据输出到控制台
  "e4b8ade59bbd"

一旦数据载入JVM中,就以unicode码的形式存在JVM中,此时并没有具体的编码格式,这时,你可以将数据转为任意编码格式。

public class Test {
	public static void main(String[] args) throws UnsupportedEncodingException {
	    /**
	     * 数据以unicode码的形式载入JVM中,此时你可以将其转为任意编码格式
	     */
		String str = "中国";
		System.out.println(toHexString(str.getBytes()));  // e4b8ade59bbd  系统默认UTF-8
		System.out.println(toHexString(str.getBytes("GBK"))); // d6d0b9fa GB2312
		System.out.println(toHexString(str.getBytes("GB2312"))); // d6d0b9fa GBK
		System.out.println(toHexString(str.getBytes("UTF-8"))); // e4b8ade59bbd UTF-8
		System.out.println(toHexString(str.getBytes("UTF-16"))); // feff4e2d56fd UTF-16
	}

	public static String toHexString(byte[] data) {
		final int l = data.length;
		final char[] out = new char[l << 1];

		for (int i = 0, j = 0; i < l; i++) {
			out[j++] = DIGITS_LOWER[(0xF0 & data[i]) >>> 4];
			out[j++] = DIGITS_LOWER[(0x0F & data[i])];
		}

		return new String(out);
	}

	final static char[] DIGITS_LOWER = { '0', '1', '2', '3', '4', '5', '6',
			'7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
}

在下面这个例子中,字符串数据以GBK编码格式载入在JVM中,然后进行输出,控制台的编码格式为UTF-8。

@Test
public void gbk_unicode_utf8() throws DecoderException,
		UnsupportedEncodingException {

	byte[] bytes = Hex.decodeHex("d6d0b9fa".toCharArray());
	String str = new String(bytes, "GBK"); // 转成字符串数据,此时str是unicode编码

	System.out.println(str); // 输出"中国"
}

在这个过程中,我们并没有将GBK格式数据转为UTF-8,而是JVM隐式地将GBK数据转为unicode码,然后再输出时根据控制台的编码再转为UTF-8编码格式。JVM相当于一个中间人,解耦了GBK与UTF-8,不必考虑原始编码与目标编码不一致而导致乱码的输出。

字节流 vs 字符流

我们在操作IO流的时候,可以获取字节流和字符流。字节流就是IO的二进制形式,由于计算机最小的操作单元的字节,所以我们称之为字节流。 例如一个文件的二进制位01001010(对应ASCII字符J),则读取到字节流中也为01001010,使用十六进制表示二级制,输出的结果为4A

而如果使用字符流的形式读取IO流时,JVM则会使用指定编码(如果没指定,则使用系统默认编码)来对10序列进行读取,然后统一转为unicode编码,同样是"01001010"载入到JVM中后则变成了unicode序列FEFF004A

实际上,这里的unicode编码对应的是unicode的UTF-16编码。以16位定长的二进制表示一个unicode码。

参考资料