字符集编码问题


下面这三段代码在效果上有什么区别?


 使用2次utf-8
   // decode with base64 to get bytes
    byte[] dec = BASE64DecoderStream.decode(str.getBytes("UTF-8"));   使用1次utf-8
    byte[] utf8 = dcipher.doFinal(dec);  
    // create new string based on the specified charset
    return new String(utf8, "UTF8");   使用1次utf-8


 // decode with base64 to get bytes
    byte[] dec = BASE64DecoderStream.decode(str.getBytes());
    byte[] utf8 = dcipher.doFinal(dec);
    // create new string based on the specified charset
    return new String(utf8, "UTF8");使用1次utf-8


 使用1次utf-8
   // decode with base64 to get bytes
    byte[] dec = BASE64DecoderStream.decode(str.getBytes("UTF-8"));   使用1次utf-8
    byte[] utf8 = dcipher.doFinal(dec);
    // create new string based on the specified charset
    return new String(utf8);

java 字符编码

西瓦的守护 9 years, 2 months ago

使用1次 使用2次 这个提法没到点上,这里次数根本不是关键。

牵扯到编码的问题,首先要认识到Java的String是无关编码的,它存储的是字符数据,而不是字节数据(尽管底层使用Unicode进行存储)
但是我们在处理各种数据的事后,总是会接触各种各样的文字的编码,比如保存进入文件时,或者进行网络传输时,这时候我们关心的是字节数据,而不是字符。

String对象的getBytes方法就是提供了编码转换成字节数据的方式,对于字节数据到低怎么编码这时候就开始需要关心了。它有多个重载,拿LZ关心的这两个来说就是


 public byte[] getBytes();
public byte[] getBytes(String charsetName)
                throws UnsupportedEncodingException;

这两个方法的区别其实去翻翻Java API手册就知道,前者是获取了系统当前默认编码进行编码,后者则是通过charsetName参数指定编码

同理来看String的构造方法


 public String(byte[] bytes);
public String(byte[] bytes, String charsetName);

前者使用系统当前默认编码来把byte数组里面的数据解码为字符,后者通过charsetName参数指定编码

PS: 如果还是不能理解字节和字符,那么请这样考虑:一个汉字作为字符来说,是一个不可分割的个体,但是它如果用GB18030(GBK/GB2312)编码进行标示,则是2个字节长度的byte[],如果用UTF8,则是3个字节长度的byte[]

雾雨店D魔理沙 answered 9 years, 2 months ago

关于字符编码,可以参考阮大神的 字符编码笔记:ASCII,Unicode和UTF-8 ,尤其是里面 UTF8 的部分。这里需要用到的一个关键信息是:对于 ASCII 码为 0-127的字符,UTF8编码和ASCII编码是相同的(原文说的是对于英语字母,但其实英文字母只是其中一部分)。

现在来说你的代码

先说 String.getBytes() ,这个方法没有指定编码,会使用系统默认的编码,对于中文 Windows 系统来说,就是 GBK 编码。

BASE64DecoderStream.decode(str.getBytes("UTF-8")) 这调用判断,str 里保存的是 Base64 编码,由 [a-zA-Z0-9+/] 这 64 个字符组成,ASCII 范围都在 0-127 之间,所以 getBytes() getBytes("utf-8") 的区别就在于 GBK 和 UTF8 —— 而在刚才说的字符范围内,这两个编码其实没有区别,也就是说,这里你使用不使用 UTF8,结果是一样的。

然后你的代码,将 base64 解码的结果进行了解密(加密解密都有可能,从逻辑上来判断,更像是解密)。至于解决的结果,是 byte[]。

OK,到这一步,你得到了 byte[] 的 utf8 ,这里 utf8 只是一个变量,通常会提醒读者其保存的数据是 UTF8 编码的。顺便提一下,计算机世界,所有东西都是二进制保存,而保存的基本单位是字节,所以 utf8 中保存的是啥,从目前这点程序来看,根本看不出来,只有写程序的人知道。

所以,不管变量名是否 UTF8,你得知道 utf8 中的数据实际什么,只在这个数据的确是一段文本,而且使的编码明确的情况下,按这个编码生成字符串才能得到正确的结果。

僕等がいた answered 9 years, 2 months ago

Your Answer