有用的资料
最近在字符编码上遇到一些问题,查阅了很多资料,有了一点领悟。以下是几个比较重要的资料:
《彻底搞懂字符编码》:http://blog.youkuaiyun.com/softman11/article/details/6124345
《深入分析 Java 中的中文编码问题》:http://www.ibm.com/developerworks/cn/java/j-lo-chinesecoding/
看了以上两篇文章,基本就能搞懂字符编码问题了。
下面是关于Java的字符编码问题的一个帖子,解释了Java的String中的字符存储问题:
http://stackoverflow.com/questions/12187645/java-utf8-encoding-char-string-types
个人小结:
在任何平台上,String中的char[]都是UTF-16类型的数组。String的所有操作都是在这个char[]上完成的。
Java的String是一个中间结果,可以通过getBytes(charset)函数得到指定编码的byte[]。
String.getBytes(charset)实际上是将UTF-16数组按照对应的charset编码为byte[]。网络程序中,将byte[]传输到其他平台,其他平台再用new String(byte[], charset)将byte[]转化为该平台本地的UTF-16字符串。
网上有一种转化字符串编码的方法:
String newString=new String(oldString.getBytes(oldCharSet),newCharSet),这种方式实际上没有任何意义,纯属误导。下面简单解释一下。
以上转换的初衷通常是想在控制台(或文件)输出字符串。乱码是由于控制台(或文件)通常是GBK或UTF-8的,而String的char[]是UTF-16类型的。这时就需要使用 String.getBytes("GBK") 或者 String.getBytes("UTF-8") 得到byte[],然后使用 OutputStream.write(byte[]) 即可得到正确的输出。
另外,UTF-8通常比较省空间,一般通过String.getBytes("UTF-8")得到byte[],再进行网络传输。
示例程序
下面的程序简单的展示了这个过程:
import java.io.*;
public class TestCharSetConvert {
/*程序功能:
* 从文件中读入数据,以其他编码输出到其他文件中
*/
public static void main(String[] args){
//首先在程序目录下创建一个GBK编码的名为GBK.txt,里面可以包含任何汉字和英文等
String inCharsetName="GBK";
String[] outCharsetNames=new String[]{"GBK","GB2312","Unicode","UTF-8","UTF-16"};
String content=readStringByStream(inCharsetName+".txt",inCharsetName);
for(String outCharsetName: outCharsetNames){
writeStringByStream(content,outCharsetName+".txt",outCharsetName);
}
}
public static String readStringByStream(String inFilePath, String inCharsetName){
try {
FileInputStream fin=new FileInputStream(inFilePath);
byte[] bytes=new byte[1024];
int count=fin.read(bytes);
String content=new String(bytes,0,count,inCharsetName);//解码为UTF-16字符串,inCharsetName必须与文件的字符编码一致,否则会失败或产生乱码
System.out.format("read %s from %s with charset %s\n\n",content,inFilePath,inCharsetName);
fin.close();
return content;
}
catch (Exception e) {
e.printStackTrace();
}
return "";
}
public static void writeStringByStream(String content, String outFilePath, String outCharsetName){
try {
FileOutputStream fout=new FileOutputStream(outFilePath);
byte[] bytes=content.getBytes(outCharsetName);//将UTF-16字符串编码为指定字符集的字节流
fout.write(bytes);
fout.close();
System.out.format("wrote %s to %s with charset %s\n",content,outFilePath,outCharsetName);
}
catch (Exception e) {
e.printStackTrace();
}
}
}
以上程序使用了InputStream和OutputStream以字节流的方式输入输出。实际上Java的Reader和Writer已经封装了这个过程,可以使用它们进行面向字符和字符串的操作。