java 中的编码问题
一、编码格式:
1.ASCII 总共128个 2.ISO-8859-1 共256个,涵盖了大部分西欧语言字符 3.GB2312 包含682个符号,6763个汉字
4.GBK兼容GB3212,包含21003个汉字 5.GB13030 兼容GB2312 《信息交换用汉字编码字符集》 国家标准
6.UTF-16 Unicode编码,用两个字节表示一个字符,java中以UTF-16作为内存中的字符存储格式。
7.UTF-8 采用变长技术,每个编码区域有不同的字码长度,不同类型的字符可以由1~6个字节组成。
二、java中的编码场景
1.I/O操作中的编码操作
//写入文件
String file="c:/a.txt";
String charset="UTF-8";
FileOutputStram os =new FileOutputStram(file);
OutputStreamWriter writer=new OutputStreamWriter(os,charset);//如果此处不设置charset会有默认值
try{
writer.write("这是保存的中文字符");
}finally{
writer.close();
}
//读取文件
FileInputStream is=new FileInputStream();
InputStreamReader reader=new InputStreamReader(is,charset);//读文件时charset必须与写文件时一致或兼容,否则会乱码
StringBuilder sb=new StringBuilder();
char[] buf = new char[64];
int count = 0;
try{
while(count = reader.read(buf)){
sb.append(buf,0,count);
}
}finally{
reader.close();
}
2.内存中的编码操作
//字符串与字节数组之间的转换
String str="这是一段中文字符";
byte[] b=srt.getBytes("UTF-8");//将字符串转换成byte数组,必须设置编码格式,否则使用默认值
String n=new String(b,"UTF-8");
//字符串  编码成字节数组  解码成字符数组
String str="这是一段中文字符";
Charset charset=Charset.forName("UTF-8");
ByteBuffer byteBuffer=charset.encode(str);
CharBuffer charBuffer=charset.decode(byteBuffer);
三、编码格式比较
GBK与GB2312,GBK可以处理所有的中文字符,而GB2312则有许多字符处理不了,所以应选择GBK。
UTF-8与UTF-16,都是处理Unicode编码,两者编码规则不相同,相对来说UTF-16编码效率高,任何字符都使用两个字节16位来存储,字符到字
节之间的转换更简单,进行字符串操作也更好,适合在本地磁盘与内存之间使用,java在内存中的编码使用UTF-16。UTF-16编码成的字节流在
传输过程中如果出现数据丢失则,所有数据都将导致解码失败。UTF-8变长编码,针对ASCII字符采用单字节存储,适合网络传输,每个字符都
有开始和结束的识别信息,网络传输过程中,如果不分数据丢失,解码时仅仅是丢失不分不能解码。UTF-8编码效率介于UTF-16与GBK之间,
UTF-8在编码效率上和编码安全上做了平衡,是理想的中文编码方式。
四、java Web中设计的编码与解码
1.Web中存在编解码的地方:
用户从浏览器发送一个HTTP请求到服务器,需要编码的地方有:URL,Cookie,parameter。服务器接收到请求后需要解码的地方有URI,Cookie
,post表单参数。服务器端可能还需要读取数据库中的数据,读取本地或网络中的其他文件,等等。服务端处理完请求后还需要将数据再编码
然后通过socket发送到用户的浏览器里。浏览器再将相应信息解码并展示出来。
2.URL的编解码的地方
连接的组成部分:如下链接
http://www.360buy.com/团购/Search?keyword=中跟鞋(此链接仅是个例子)
此链接可分为几个部分:①scheme:http:②域名:www.360buy.com③URI:团购/Search④queryString:keyword=中跟鞋
URI(/团购/Search)中如果有中文,编码在Tomcat中设置,<connector URIEncoding="UTF-8"/>,如果没有定义,则使用默认的iso-8859-1进
行编解码。
queryString(keyword=中跟鞋)中如果有中文,此部分是编码设置在tomcat中,<connector URIEncoding="UTF-8" 
useBodyEncodingForURI="true"/>,如果这样设置,则编码方式与URI的编码格式一致,如果不设置useBodyEncodingForURI="true",则使用默认
的编码格式,不同浏览器有不同的默认值。解码则是在第一次调用request.getParameter("...")时进行解码的,如果设置了
useBodyEncodingForURI="true",则可以默认使用URIEncoding="UTF-8"设置的参数进行解码。
在使用get请求的时候参数最好不要使用中文,比较容易出现乱码问题。URI部分也不建议使用中文。Tomcat中最好设置成<connector 
URIEncoding="UTF-8" useBodyEncodingForURI="true"/>,并保持整个应用中编解码都一致。
3.post请求的编解码:
在客户端使用post提交表单时,首先在客户端会使用ContentType 中设置的charset对表单进行编码,在服务端第一次调用
request.getParameter("...")时也会自动使用ContentType 中设置的charset进行解码,当然还可以在第一次调用request.getParameter
("...")之前,通过request.setCharacterEncoding(charset)来设置解码方式。post提交表单一般不会出现问题。
4.HTTP Header的编解码
先说解码,Header中的解码也是在第一次调用request,getHeader()时进行解码的,如果调用时还没有解码,则调用MessageBytes.toString方
法,这个方法将从byte到char使用默认的ISO-8859-1进行解码。此处不能设置Header的其他解码格式,所以如果Header中有非ASCII字符则必然
会乱码。如果在Header中必须有中文则必须显示将其转换成ASCII字符。
5.HTTP body中的编解码
编码:通过response.setCharacterEncoding(charset)进行编码,数据传输到浏览器后,通过Header中的<meta HTTP-equiv="Content-Type" 
content="text/html";charset=UTF-8"/>中的charset来进行解码,如果没有设置,则使用浏览器默认的解码方式。