ASCII,ISO-8859-1,GB2312,GNBK,UTF-8,UTF-16等
编码格式 | 表示个数 | 所需字节数 | 说明 |
---|---|---|---|
ASCII | 128 | 单字节的低七位表示 | 0~31为控制字符如回车换行等;32~126为打印字符,可键盘输入能够显示出来 |
ISO-8859-1 | 表示256个字符 | 单字节 | 扩展ASCII码,ISO8859-1到ISO8859-15,ISO8859-涵盖大多数西欧语言字符,应用最广泛。 |
GB2312 | 7445 | 双字节 | A1~A9是符号区,682个;B0~F7是汉字区,共6763个汉字。 |
GBK | 23940 | 双字节 | 扩展自GB2312,支持更多汉字,范围从8140~FEFE(去掉XX7F),能表示21003汉字,兼容GB2312。 |
GBK18030 | 兼容GB2312 | 应用不广泛 | 应用不广泛 |
UTF-16 | 处理Unicode编码 | 双字节 | 用2字节表示Unicode的转化格式,任何字符都通过2个字节表示,定长表示,效率快,java以UTF-16内存的字符存储格式。适合在本地磁盘和内存之间使用,可以达到字符和字节快速切换。 |
UTF-8 | 处理unicode编码 | 变长 | 每个编码区域不同字码长度,不同类型字符可以由1~6个字节组成,节省空间,效率不如utf-16,介于gbk和uft-16之间,适合网络传输,对ASCII码单字节存储,单字符损坏不影响后面字符。其通过首字节的前2位确定需要几个字节表示。 |
说明:unicode是统一码,ISO创建的全新的超语言字典,所有语言都可以通过这个字典相互翻译。
1.磁盘I/O操作中存在的编码
Reader类是java中读取字符的父类
InputStream是读取字节的父类
InputStreamReader类是关联字节到字符的桥梁,它负责在I/O中处理字节到字符的转换
具体字节到字符的解码实现它委托StreamDecoder类去做,在解码过程中必须由用户指定通过Charset指定编码格式,如果不指定会使用系统自带的编码格式.
Writer,OutputStream,OutputStreamWriter类的情况类似.
例如
String file = "D:/a.txt";
String charset = "UTF-8";
//写字符转化为字节流
FileOutputStream outputStream = new FileOutputStream(file);
//创建OutputStreamWriter对象
OutputStreamWriter writer = new OutputStreamWriter(outputStream,charset);
writer.write("这是内容");
writer.close();
//读取字节转化为字符
FileInputStream inputStream = new FileInputStream(file);
//创建InputStreamReader
InputStreamReader reader = new InputStreamReader(inputStream,charset);
//创建拼接字符串
StringBuffer stringBuffer = new StringBuffer();
char[] buf = new char[64];
int count = 0;
while ((count = reader.read(buf)) != -1){
stringBuffer.append(stringBuffer,0,count);
}
reader.close();
2.内存操作中编码
2.1 String提供了转换字节的方法
String s = "内容";
//字符串转换为字符数组
buye[] b = s.getBytes("UTF-8);
//字符数组转换为字符串
String n = new String(b,"UTF-8");
2.2 Charset类
//规定编码
Charset charset = Charset.forName("UTF-8");
//字符转换为字节
ByteBuffer buf = charset.encode("内容");
//字节转换为字符
CharBuffer buf2 = charset.decode(buf);
2.3 ByteBuffer类
ByteBuffer的用法:
//字符转换为字节
//创建一个容量为256字节的ByteBuffer
ByteBuffer buf = ByteBuffer.allocate(1024);
ByteBuffer buf1 = buf.putChar(c);
1.GB2312与GBK
GBK是GB2312的升级版,GBK可以处理所有的汉字字符,而GB2312包含的中文字符不全,所以GB2312和GBK去比较,应该选择GBK
2.UTF-16和UTF-8
UTF-16编码效率最高,但不适合网络之间传输,占用空间也比较大,因为全部编码为双字节
UTF-8编码效率处在UTF-16和GBK之间,适合网络传输数据,是理想的中文编码方式
1.网络I/O操作中存在的编码
1.1 数据经过网络传输都是以字节为单位的,则所有的数据都必须能够被序列化字节.
1.2 用户的一个HTTP请求,所需要编码的地方:URL,Cookie,Paramiter.
1.3 URL编解码:引用大佬的博客,写的非常详细
http://www.cnblogs.com/liuhongfeng/p/5006341.html
1.4 HTTP Header编码
在Header中传递的参数包含Cookie,redirectPath等.
如果在Header中传递非ASCII字符时,需要将这些字符用org.apache.catalina.util.URLEncoder编码才可.
1.5 POST表单的编解码
POST表单提交的参数的解码在第一次调用request.getParameter时发生,POST表单参数通过http的body传递到服务端。
整个流程是点提交时,浏览器根据contenttype的charset对表单参数编码,提交到服务端,服务端同样用contenttype中的字符集进行解码,所以post表单的参数一般不会乱码。
通过request.setCharacterEncoding(charset)可以设置。
注意:要在第一次调用request.getParameter方法之前设置request.setCharacterEncoding(charset),否则POST表单提交的数据可能出现乱码。
1.6 HTTP BODY编解码
服务端返回的结果经过编码返回浏览器,浏览器解码,然后显示。
编码可以通过response.setCharacterEncoding设置,会覆盖request.setCharacterEncoding的值,通过Header的content-type返回给客户端。
浏览器首先根据Content-type解码,无则根据HTML的来解码,无则使用浏览器默认编码解码。
2.JS中的编码问题
2.1 js文件编解码
<html>
<head>
<script src="xxx/a.js" charset="gbk"/>
引入的js文件若有中文,和本html页面的编码若不一致则会乱码,可以手动指定编码格式。
2.2 js的url编解码
js中发起ajax请求的url默认编码受浏览器不同影响,可使用encodeURI()、encodeURIComponent()几个函数。
encodeURL():可以将整个URL中的字符进行UTF-8编码,在背个码值之前添加"%"
注意:java中的URLEncoder、URLDecoder和js的encodeURIComponent对应。
2.3 xml文件的编解码
xml文件开始设定encoding
2.4 velocity模板设置编码
services.VelocityService.input.encoding=UTF-8
2.5 jsp设置编码
jsp页面<%@page >里面设置charset
1.中文变成了看不懂的字符
因为字符串解码时使用的字符集和编码字符集使用不一致所导致的.将字符集使用一致即可
2.中文变成了问号,一个中文变为一个问号
因为该字符串经过了不支持中文的ISO-8859-1编码后所出现的问题.换为GBK或者UTF-8即可
3.中文变成了问号,一个中文变为两个问号
这种情况比较复杂,中文经过了多次编码才会出现,需要检查中间的编码环节才可.
4.使用request.getParameter(name);出现乱码
因为配置文件中将useBodyEncodingForURL配置项没有设置为true,从而造成第一次解析用ISO-8859-1来解析.设置为true即可.
--本博文为博主在学习《深入分析java web 技术内幕》一书时所写。这本书不错,推荐给大家。
--本博文书写借鉴了博友的博客,在此表示感谢.