Java字符转码
1.关于文件转码
这里我对字符串进行了二进制解码和编码。
首先你要知道以下几点。
1.生活中的文字转成二进制格式的序列或其他格式的序列,叫做编码过程。而对二进制序列或其他格式序列解析成生活中的文字,叫做解码过程。
2.Java的string内部是用Unicode编码的字节数组存储字符串的,如果你Java源文件编码方式是GBK,那么JVM会以GBK读取源文件中“”双引号的字符串,将读取的GBK编码字节解析成字符,然后再对字符以Unicode编码成字节数组,并存储于内部。
3.无论你源文件以那种方式编写字符串,JVM最终都会对“双引号”字符进行转码成Unicode格式并存用string对象内部。
4.string.getBytes()方法是根据你平台或源文件默认的编码方式进行encoding(编码),放回的是编码后的字节数组。string.getBytes(String charsetName)能指定编码方式,不用担心内部Unicode编码->charsetName编码,Java会帮你处理这个过程。
5.new String(byte[] b,String charsetName)这个构造函数将对指定的byte[] b指定编码解析。
下面我举几个例子:
String src ="你好朋友"; //string的内部编码方式是Unicode
byte[] U = src.getBytes(); //我的project的文件使用的是 UTF-8 encoding,所以这里返回 UTF-8编码的字节数组
byte[] G = src.getBytes("GBK");
System.out.println(src.length());
System.out.println(U.length);
System.out.println(G.length);
System.out.println(Charset.defaultCharset()); //打印编译器默认编码格式
String str1 = new String(src.getBytes("utf-8"),"utf-8");
String str2 = new String(src.getBytes("utf-8"),"gb18030");
String str3 = new String(src.getBytes("utf-8"),"GBK");
String str4 = new String(src.getBytes("utf-8"),"latin1");
System.out.println(String.format("%s\n%s\n%s\n%s\n", str1,str2,str3,str4));
String str5 = new String(src.getBytes("GBK"),"utf-8");
String str6 = new String(src.getBytes("GBK"),"gb18030");
String str7 = new String(src.getBytes("GBK"),"GBK");
String str8 = new String(src.getBytes("GBK"),"latin1");
System.out.println(String.format("%s\n%s\n%s\n%s\n", str5,str6,str7,str8));
运行结果如下:
4 //字符串长度
12 //平台默认编码为UTF-8,中文一个字占3字节,所以是12
8 //指定放回的GBK编码,一个中文2字节,所以是8
UTF-8 //默认编码(编译器或源文件编码方式)
你好朋友 //编码和解析方式一样,能成功解析
浣犲ソ鏈嬪弸 //utf-8编码的字节数组,指定解析方式为gb18030,不能能成功解析
浣犲ソ鏈嬪弸 //同理
ä½ å¥½æœ‹å‹ //latin1压根不支持中文
������� //同理
你好朋友 //原因是GBK是gb18030的子集,GBK只包含汉字,gb18030包含小数民族的字
你好朋友 //编码和解析方式一样,能成功解析
ÄãºÃÅóÓÑ //latin1压根不支持中文
结果分析:
1.new String(src.getBytes(“GBK”),“utf-8”);压根不是进行转码,这个是编码和解码过程。编码和解析方式不同,根本无法正常显示,这里解码有误过程,也非真正的转码。网上一些教程有错误。src.getBytes(“GBK”)只有这句内部进行了转码(Unicode——>GBK,返回了对应的字节数组。
文件转码的正确方式:
第一步:以正确的方式打开并读取文件(我这里是UTF-8文件).
第二步:将字符串读取出来,并使用getBytes(“GBK”)获取对应的编码的二进制数据。
第三步:将编码后的二进制数据以二进制的方式写入到文件中。(无需解析,直接存进去就可以了)
第四步:关闭输入输出流。
String path = "D:\\SogouQ\\access_log.20060803.decode.filter";
String path2 = "D:\\mytext.txt";
BufferedReader br=null;
BufferedOutputStream bo=null;
try {
br = new BufferedReader(new InputStreamReader(new FileInputStream(path),"utf-8"));
bo =new BufferedOutputStream(new FileOutputStream(path2));
String line = null;
while ((line = br.readLine())!=null) {
line=line+"\n";
bo.write(line.getBytes("GBK"));
}
}catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
try {
br.close();
bo.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
2.URL编码
URL 只能使用 ASCII来通过因特网进行发送。由于 URL 常常会包含 ASCII 集合之外的字符,URL 必须转换为有效的 ASCII 格式。URL 编码使用 “%” 其后跟随两位的十六进制数来替换非 ASCII 字符。又因为我们日常生活中往往会用好很多字符,而URL又只能用ASCII,所以这里需要URL编码。
下面举个例子:
String src ="你好朋友";
String text1 = URLEncoder.encode(src, "utf-8"); //将UTF-8字符变成ASCII字符
String text2 = URLEncoder.encode(src, "gb18030");
String text3 = URLEncoder.encode(src, "GBK");
String text4 = URLEncoder.encode(src, "latin1");
System.out.println(String.format("%s\n%s\n%s\n%s\n", text1,text2,text3,text4));
String text5 = URLDecoder.decode(text1, "utf-8");
String text6 = URLDecoder.decode(text2, "gb18030");
String text7 = URLDecoder.decode(text3, "GBK");
String text8 = URLDecoder.decode(text4, "latin1");
System.out.println(String.format("%s\n%s\n%s\n%s\n", text5,text6,text7,text8));
输出结果:
%E4%BD%A0%E5%A5%BD%E6%9C%8B%E5%8F%8B //一个字节编码成3个符号(% + 2个16进制数)
%C4%E3%BA%C3%C5%F3%D3%D1
%C4%E3%BA%C3%C5%F3%D3%D1
%3F%3F%3F%3F //Latin不支持中文,所以都是%3F
你好朋友
你好朋友
你好朋友
???? //Latin不支持中文