当面对一串字节流的时候,如果不指定它的编码,其实际意义是无法知道的。
这句话应该也是我们面对“字符转字节,字节转字符”问题时候时刻记在脑子里的。否则乱码问题可能就接踵而至。
其实乱码问题的本质就是Encoding和Decoding用的不是一个编码,明白了这个道理就很好解决乱码问题了。
Java中常见的时候有如下:
1. String类使用byte[]的构造函数 String(byte[] bytes),String类同时提供了两个重载
(1)String(byte[] bytes, Charset charset)
(2)String(byte[] bytes, String charsetName) 就是用来指定编码的。
2. String类的getBytes函数 byte[] getBytes() 同样有如下两个重载:
(1)byte[] getBytes(Charset charset)
(2) byte[] getBytes(String charsetName)
所有不需指定编码的都是使用the platform's default charset, 可使用System.getProperty("file.encoding"),Charset.defaultCharset()获的。
3. PrintStream的 print(String s)同样设计到这个问题,为此PrintStream的构造函数中除了PrintStream(File file) 还有PrintStream(File file, String csn)
否则the string's characters are converted into bytes according to the platform's default character encoding,
DataOutputStream构造时没有方法指定编码,但其提供了一个writeUTF(String str)
举开头的例子说明指定编码的必要:
如果一个网页指定编码为utf-8, <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />, 页面上有一个form,提交到一个servlet
那么用户输入的字符传过来的字节流就是按指定编码encoding的,例如你输入了"Hello你好",如果是utf-8,那么传过来的就是如下:
1
|
[104, 101, 108, 108, 111, -28, -67, -96, -27, -91, -67] |
, 我们看到后面汉字每个用了3个字节,这个可以参考Utf-8的相关知识。
但如果你页面指定的是GBK,那传过来的就不一样了:
1
|
[104, 101, 108, 108, 111, -60, -29, -70, -61] |
所以servlet端,当使用request.getParameter的时候内部应该是调用
String s = new String(bytes, response.getEncoding())的,如果你response没有设置编码,那么就采用默认的编码null会转为java 平台的GBK,那中文就变成乱码了。
所以为了避免乱码,jsp站点一般设一个过滤器,所有的页面、servet都设置统一的编码。response.setEncoding, request.setEncoding.
Java的String内部是一个char[], char是一个用16位存储的utf-16编码的单元。为此,当要把字符、字符串转为字节输出到文件、网络,或者从文件、网络读到的字节流还原为有实际意义的字符,都要明白其编码是什么。
几点心得
1.String类始终是以Unicode编码形式存储.
2.注意String.getBytes()的使用:
如果不带字符集参数,就会依赖于JVM的字符集编码,LINUX上一般为UNICODE,WINDOWS下一般为GBK.(要想改变JVM缺省字符集编码,启动JVM时用选项-Dfile.encodeing=UTF-8.
为了安全起见,建议始终带参数调用,例如:String s ; s.getBytes("UTF-8")。
3.Charset类非常好用,
(1)Charset.encode 是编码,即把String按你指定的字符集编码格式进行编码后输出字节数组。
(2)Charset.decode 是解码,即把一个字节数组按你指定的字符集编码格式进行解码后输出成字符串。
举例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
String s = Charset.defaultCharset().displayName(); String s1 = "我喜欢你,My Love" ; ByteBuffer bb1 = ByteBuffer.wrap(s1.getBytes( "UTF-8" )); for ( byte bt:bb1.array()){ System.out.printf( "%x" ,bt); } //char[]用法 char [] chArray={ 'I' , 'L' , 'o' , 'v' , 'e' , '你' }; //CharBuffer用法 CharBuffer cb = CharBuffer.wrap(chArray); //重新定位指针 cb.flip(); String s2= new String(chArray); //ByteBuffer用法 ByteBuffer bb2 = Charset.forName( "utf-8" ).encode(cb); // 利用Charset编码为指定字符集 ByteBuffer bb3 = Charset.forName( "utf-8" ).encode(s1); byte [] b = bb3.array() ; // 利用Charset按指定字符集解码为字符串 ByteBuffer bb4= ByteBuffer.wrap(b); String s2 = Charset.forName( "utf-8" ).decode(bb4).toString(); |