菜鸟笔记
提升您的技术认知

Java 字符串的编码解码

结合别人的内容和自己的理解规范地整理出,做以笔记

一、认识编码

.编码:规定每个“字符”分别用一个字节还是多个字节存储,用哪些字节来存储,这个规定就叫做“编码” 平常我们所说的“字符集”,比如:GB2312, GBK, JIS 等;

二、Java中常用的字符串的编码解码

1.将字符串转换成byte数组再恢复:

byte[] getBytes(String charsetName)

String(byte[] bytes, String charsetName)

或getBytes()

String(byte[] bytes)

2.使用String sun.misc.BASE64Encode.encode(byte[] b)

byte[] String sun.misc.BASE64Decode.decodeBuffer(String str)

将字符串转换成byte[],再转换成ASCII码;恢复时做逆操作。

在字符串转换成byte[]时,尽量用byte[] getBytes(String charsetName)方法,解码时也用相同的charsetName做参数,如果都不charsetName可能会导致一些中文字符不能正确解码。

3.使用java.net.URLEncoder类和java.net.URLDecoder类

它有static方法将字符串转换成‘pplication/x-www-form-urlencoded'格式便于在网络中传播

形如‘%20%35'。

三、系统的了解Java对字符串的编码和解码

 1. getBytes(charset) 这是 java 字符串处理的一个标准函数,其作用是将字符串所表示的字符按照 charset 编码,并以字节方式表示。注意字符串在 java 内存中总是按 unicode 编码存储的。当Java程序从输入流、文件或字符文字量等途径获得字符串时,均会做字符编码的转换,例如InputStreamReader 的构造函数中就需要指定编码方式,而对于从文件和字符文字量中获得字符串时,均采用系统默认的编码方式对字符数据进行解码。考虑下面一段代码: String str=”中”;

 

① byte[] bytes = str.getBytes();

 

② bytes = str.getBytes(“ISO-8859-1”);

③ 语句①:将一个只含有一个字符“中”的字符串文字量赋给 String 类的一个对象 str,字符文字量“中”是按照操作系统默认编码方式进行编码,在中文 windows 系统中通常是“GBK”,“中”在GBK编码中是0xD6D0,在将该字符赋给str时,Java会对该字符串进行编码转换,即将GBK编码方式的“中”转换成Unicode编码方式的“中”,Unicode编码方式“中”的编码是0x4E2D,所以str在程序运行期间在内存中的二进制表示成16进制就是0x4E2D。语句②:获得str字符串的二进制形式。getBytes(String encoding)方法需要指定编码方式,表示获得该字符串在何种编码方式中的二进制形式。此语句中没有设置参数,表示采用操作系统默认的编码方式,即此处获得的bytes是“中”在GBK编码中的二进制形式,即bytes[0]=0xD6, bytes[1]=0xD0。语句③:该语句与语句②的区别就是指定了编码方式,此处指定的是ISO-8859-1,即通常所说的Latin-1,该编码采用8bit对字符编码,所以编码空间中只有256个字符。该编码中只包含了基本的ASCII码和一些扩展的其它西欧字符,所以该字符集中不可能包含中文的“中”字,也就是说Java虚拟机无法在ISO-8859-1编码集中找到“中”字对应的编码,针对这种情况,就只返回一个问号(?,0x3f)字符,所以此时bytes.length只有1,且bytes[0]=0x3f。

 

2.new String(byte[] bytes, String encoding) getBytes()方法从字符串获得二进制的字节数组。如果要从二进制的字节数组获得字符串,则就需要使用new String(byte[] bytes, String encoding)方法,该方法按照encoding编码方法对字节数组bytes中的二进制数组进行解析,生成一个新的字符串对象。

 

byte[] bytes = {(byte)0xD6, (byte)0xD0, (byte)0x31};

 

① String str = new String(bytes);

 

② str = new String(bytes,”ISO-8859-1”);

 

 ③ 语句①:定义一个字节数组。语句②:将该字节数组中的二进制数据按照默认的编码方式(GBK)编码成字符串,我们知道GBK中0xD6 0xD0表示“中”,0x31表示字符“1”(GBK兼容ASCII,但不兼容ISO-8859-1除ASCII之外的部分),所以str得到的值是“中1”。语句③:该句用ISO-8859-1编码方式对该字节数据进行编码,由于在ISO-8859-1编码方式中一个字节会被解析成一个字符,所以该字节数组会被解释成包含三个字符的字符串,但由于在ISO-8859-1编码方式中没有对应0xD6和0xD0的字符,所以前两个字符会产生两个问号,由于0x31在ISO-8859-1编码中对应字符“1”(ISO-8859-1也兼容ASCII),所以此语句得到str的值是“??1”。

 3.setCharacterEncoding() 该函数用来设置http请求或者相应的编码。对于request,是指提交内容的编码,指定后可以通过getParameter()直接获得正确的字符串,如果不指定,则默认使用iso8859-1 编码,需要进一步处理。值得注意的是在执行setCharacterEncoding()之前,不能执行任何 getParameter()。而且,该指定只对POST方法有效,对GET方法无效。分析原因,应该是在执行第一个getParameter()的时候,java将会按照编码分析所有的提交内容,而后续的getParameter()不再进行分析,所以setCharacterEncoding()无效。而对于GET方法提交表单时,提交的内容在URL中,一开始就已经按照编码分析所有的提交内容,setCharacterEncoding()自然就无效。对于response,则是指定输出内容的编码,同时,该设置会传递给浏览器,告诉浏览器输出内容所采用的编码。

 四、页面编码页面编码

页面的编码格式可以从两方面来说明:

  • 一是页面本身的编码格式,即以什么编码方式保存;
  • 二是客户端浏览器以什么编码格式显示页面。

1. 页面保存编码格式

 

1). HTML 页面的编码要看你保存文件时的编码选项,多数的网页编辑软件可以让你选择编码的类型,默认为本地编码,为了使网页减少编码的问题,最好保存为 UTF-8 编码格式。

 

 2). JSP 页面使用下列标签指定 JSP 源文件的编码格式,具体来说,我们在JSP源文件头上加入下面的一句即可: %@page[/email] pageEncoding="xxx"%>,xxx可以为GB2312,GBK,UTF-8(和MySQL不同,MySQL是 UTF8)等等,其默认值为ISO-8859-1。保存文件时的编码应该与xxx 一致。

2. 页面显示编码(通知客户端浏览器用什么字符集编码显示页面)

 

 1). 在 HTML 中设置页面显示编码方式 使用标签设置页面显示编码

 

2). 在 Servlet 中设置页面显示编码方式 使用 response.setContentType("text/html; charset=xxx");来指定生成的页面编码。

 

 3).在 JSP 中设置页面显示编码方式 使用设置页面显示编码。字符集的默认值为ISO-8859-1。

五、jsp 编译过程(以tomcat为例)

 

1.Tomcat 先将整个JSP页面的代码读取出来,写到一个新的JAVA文件中。在读取JSP文件时,tomcat会先去读取JSP文件的pageEncoding属性,然后按照pageEncoding指定的编码来读取JSP文件。如果pageEncoding没有指定,tomcat会使用contentType指定的字符集编码,如果contentType也没有指定,就使用默认的ISO-8859-1编码。

 

2.Tomcat读取完JSP文件后,会用UTF-8编码将这些内容写道一个新的文件中,然后编译。

 

3.当JSP文件显示的时候,会使用contentType中指定的MIME类型和charset。如果charset没有指定,就使用pageEncoding中指定的编码,如果pageEncoding也没有指定,就使用默认的ISO-8859-1编码。

六、这样使我想起之前犯的错误 原来是各自使用的编码集不相同导致的;