java中⽂乱码以及转码
查看此⽂章需要对字符集编码有⼀定的认识:任意门:
⼀、字符串的内部表⽰?
重点:字符串在java(指在JVM中、在内存中)中统⼀⽤unicode表⽰( 即utf-16 LE) , 下⾯解释:
对于 String s = "你好哦!";
如果源码⽂件(java⽂件)是GBK编码, 操作系统(windows)默认的环境编码为GBK,那么编译时, JVM将按照GBK编码将字节数组解析成字符(系统⽂件本质就是⼆进制流),然后将字符转换为unicode格式的字节数组,作为内部存储。
当打印这个字符串时,JVM 根据操作系统本地的语⾔环境,将unicode转换为GBK,然后操作系统将GBK格式的内容显⽰出来。
当源码⽂件是UTF-8, 我们需要通知编译器源码的格式,javac -encoding utf-8 ... , 编译时,JVM按照utf-8 解析成字符,然后转换为unicode格式的字节数组,所以不论源码⽂件是什么格式,同样的字符串,最后得到的unicode字节数组是完全⼀致的,显⽰的时候,也是转成GBK来显⽰(跟OS环境有关:OS表⽰操作系统)
⼆、乱码如何产⽣?本质上都是由于字符串原本的编码格式与读取时解析⽤的编码格式不⼀致导致的。例如:
String s = "你好哦!";
System.out.println( new Bytes(),"UTF-8")); //错误,因为getBytes()默认使⽤GBK编码,⽽解析时使⽤UTF-8编码,肯定出错。其中 getBytes() 是将unicode 转换为操作系统默认的格式的字节数组,即"你好哦"的 GBK格式,
java语言使用的字符码集是new String (bytes, Charset) 中的charset 是指定读取 bytes 的⽅式,这⾥指定为UTF-8,即把bytes的内容当做UTF-8 格式对待。
如下两种⽅式都会有正确的结果,因为他们的源内容编码和解析⽤的编码是⼀致的。
System.out.println( new Bytes(),"GBK"));
System.out.println( new Bytes("UTF-8"),"UTF-8"));
三、如何利⽤getBytes 和 new String() 来进⾏编码转换呢?
⽹上流传着⼀种错误的⽅法:
GBK--> UTF-8: new String( s.getBytes("GBK") , "UTF-8); ,这种⽅式是完全错误的,因为getBytes 的编码与 UTF-8 不⼀致,肯定是乱码。
但是为什么在tomcat 下,使⽤ new Bytes("iso-8859-1") ,"GBK") 却可以⽤呢?答案是:
tomcat 默认使⽤iso-8859-1编码,也就是说,如果原本字符串是GBK的,tomcat传输过程中,将GBK转成iso-8859-1了,
默认情况下,使⽤iso-8859-1读取中⽂肯定是有问题的,那么我们需要将iso-8859-1 再转成GBK,⽽iso-8859-1 是单字节编码的,
即他认为⼀个字节是⼀个字符,那么这种转换不会对原来的字节数组做任何改变,因为字节数组本来就是由单个字节组成的,
如果之前⽤GBK编码,那么转成iso-8859-1后编码内容完全没变,则 s.getBytes("iso-8859-1") 实际上还是原来GBK的编码内容
则 new Bytes("iso-8859-1") ,"GBK") 就可以正确解码了。所以说这是⼀种巧合。
四、如何正确的将GBK转UTF-8 ? (实际上是unicode转UTF-8)
String gbkStr = "你好哦!"; //源码⽂件是GBK格式,或者这个字符串是从GBK⽂件中读取出来的, JVM会把字符转化成unicode格式
//利⽤getBytes将unicode字符串转成UTF-8格式的字节数组
byte[] utf8Bytes = Bytes("UTF-8");
//然后⽤utf-8 对这个字节数组解码成新的字符串
String utf8Str = new String(utf8Bytes, "UTF-8");
简化后就是:
unicodeToUtf8 (String s) {
return new String( s.getBytes("utf-8") , "utf-8");
}
UTF-8 转GBK原理也是⼀样
return new String( s.getBytes("GBK") , "GBK");
其实核⼼⼯作都由 getBytes(charset) 做了。
getBytes 的JDK 描述:Encodes this String into a sequence of bytes using the named charset, storing the result into a new byte array.
另外对于读写⽂件,
OutputStreamWriter w1 = new OutputStreamWriter(new FileOutputStream("D:\\"),"UTF-8");
InputStreamReader( stream, charset)
可以帮助我们轻松的按照指定编码读写⽂件。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论