首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件开发 >

Java中的乱码有关问题

2012-06-29 
Java中的乱码问题Java中乱码问题很常见,原因也多种多样,这里做一个总结,不求全面,力求准确,如果错误欢迎指

Java中的乱码问题

Java中乱码问题很常见,原因也多种多样,这里做一个总结,不求全面,力求准确,如果错误欢迎指正。

?

1.文件页面编码导致的乱码。

每一个文件(java,js,jsp,html等)都有其本身的编码格式,文件中的代码在一种编码中显示正常,在另外一种编码下就会显示出乱码。
在Eclipse中,每一个工程都会有编码格式(Text file encoding), 一般默认为GBK。而一个比较好的编程习惯是新建一个项目,优先把项目的编码设为UTF-8。
这样做的原因很简单,UTF-8包含全世界所有国家需要用到的字符,是国际编码,通用性强。几种常见的字符集,GBK,GB2312,UTF-8之间的关系如下:
GBK是国家标准GB2312基础上扩容后兼容GB2312的标准。GBK、GB2312等与UTF8之间都必须通过Unicode编码才能相互转换

有兴趣了解更多,可以参考如下链接的文章,写的很好。

http://www.cnblogs.com/xiaomia/archive/2010/11/28/1890072.html

?

2.不同字符集的字符串转换时导致的乱码。
每一个String,底层实现都是用一个byte数组存储,使用不同的字符集,存储的数组长度当然就不同。如果不使用同一种字符集进行解码,就一定会出现乱码。
例如如下代码:

Java代码??Java中的乱码有关问题
  1. import?java.io.UnsupportedEncodingException;??
  2. import?java.nio.charset.Charset;??
  3. public?class?TestCharset?{??
  4. ??
  5. ????public?static?void?main(String[]?args)?throws?UnsupportedEncodingException?{??
  6. ??????????
  7. ????????String?strChineseString?=?"中文";??
  8. ????????String?encoding?=?System.getProperty("file.encoding");??
  9. ????????System.out.println("系统默认的字符集是:"?+?encoding);??
  10. ????????System.out.println(strChineseString.getBytes(Charset.forName("GBK")).length);??
  11. ????????System.out.println(strChineseString.getBytes(Charset.forName("UTF-8")).length);??
  12. ????????System.out.println(strChineseString.getBytes().length);??
  13. ????}??
  14. }??

?

输出结果为:

Java代码??Java中的乱码有关问题
  1. 系统默认的字符集是:UTF-8??
  2. 4??
  3. 6??
  4. 6??

?

可以看出,使用GBK和UTF-8编码,得到的byte数组长度不一样,原因就是utf-8使用3个字节来编码中文,而GBK使用2个字节来编码中文。因为我的项目默认使用UTF-8,所以使用不加参数的getBytes()得到的数组长度和使用UTF-8编码的 字符串长度一样。关于字符集的详细知识可以参考第一部分中给出的文章地址。

?JDK中关于getBytes方法的描述:
?getBytes()?使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。

?getBytes(Charset charset)?使用给定的 charset 将此 String 编码到 byte 序列,并将结果存储到新的 byte 数组。

每一个字符串底层都有自己的编码方式。不过一旦调用getByte方法后,得到的byte数组就是使用某种特定字符集编码后的数组,不需要再做多余的转换。

当得到上面的byte数组后,就可以调用String的另外一个方法来生成需要转码的String了。
测试例子如下:

Java代码??Java中的乱码有关问题
  1. import?java.io.UnsupportedEncodingException;??
  2. import?java.nio.charset.Charset;??
  3. public?class?TestCharset?{??
  4. ??
  5. ????public?static?void?main(String[]?args)?throws?UnsupportedEncodingException?{??
  6. ????????String?strChineseString?=?"中文";??
  7. ????????byte[]?byteGBK?=?null;??
  8. ????????byte[]?byteUTF8?=?null;??
  9. ????????byteGBK?=?strChineseString.getBytes(Charset.forName("GBK"));??
  10. ????????byteUTF8?=?strChineseString.getBytes(Charset.forName("utf-8"));??
  11. ????????System.out.println(new?String(byteGBK,"GBK"));??
  12. ????????System.out.println(new?String(byteGBK,"utf-8"));??
  13. ????????System.out.println("**************************");??
  14. ????????System.out.println(new?String(byteUTF8,"utf-8"));??
  15. ????????System.out.println(new?String(byteUTF8,"GBK"));??
  16. ????}??
  17. }??

?

输出结果为:

Java代码??Java中的乱码有关问题
  1. 中文??
  2. ??????
  3. **************************??
  4. 中文??
  5. 涓枃??

?

可以看出,使用哪种字符集编码一个String,在生成一个String的时候就必须使用相应的编码,否则就会出现乱码。
简单来讲,只有满足如下公式的String转码,才不会乱码。

Java代码??Java中的乱码有关问题
  1. String?strSource?=?"你想要转码的字符串";??
  2. String?strSomeEncoding?=?"utf-8";???//例如utf-8??
  3. String?strTarget?=?new?String?(strSource.getBytes(Charset.forName(strSomeEncoding)),?strSomeEncoding);??

?
JDK中关于getBytes方法的描述:
String(byte[] bytes)??通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String。?
String(byte[] bytes, Charset charset)??通过使用指定的 charset 解码指定的 byte 数组,构造一个新的 String。

?

3.Socket网络传输时导致的中文乱码。
使用Socket进行通讯的时候,传输有多种选择,可以使用PrintStream,也可以使用PrintWriter。传输英文还好,传输中文就可能出现乱码问题。网上的说法很多,经过实际测试,发现问题还在字节和字符的问题上面。

众所周知,Java中分为字节流和字符流,字符(char)是16bit的,字节(BYTE)是8bit的。PrintStrean是写入一串8bit的数据的。 PrintWriter是写入一串16bit的数据的。?
String缺省是用UNICODE编码,是16bit的。因此用PrintWriter写入的字符串,跨平台性好一些,PrintStream的可能会出现字符集乱码。

可以这样理解上面的话,PrintStream是用来操作byte, PrintWriter是用来操作Unicode, PrintStream一次读8bit的话,如果遇到汉字(一个汉字占16bit),就可能会出现乱码。一般需要处理中文时用PrintWriter好了。

最后网站测试,使用PrintWriter没有出现乱码。代码如下:

Java代码??Java中的乱码有关问题
  1. import?java.io.BufferedReader;??
  2. import?java.io.DataOutputStream;??
  3. import?java.io.IOException;??
  4. import?java.io.OutputStreamWriter;??
  5. import?java.io.PrintWriter;??
  6. import?java.net.Socket;??
  7. ??
  8. public?class?TestSocket?{??
  9. ??
  10. ????public?static?void?main(String[]?args)?throws?IOException?{??
  11. ????????Socket?socket?=?new?Socket();??
  12. ????????DataOutputStream?dos?=?null;??
  13. ????????PrintWriter?pw?=?null;????????
  14. ????????BufferedReader?in?=?null;??
  15. ????????String?responseXml?=?"要传输的中文";??
  16. ????????//..........??
  17. ????????dos?=?new?DataOutputStream(socket.getOutputStream());??
  18. ????????pw?=?new?PrintWriter(new?OutputStreamWriter(dos));??//不带自动刷新的Writer???????????
  19. ????????pw.println(responseXml);??
  20. ????????pw.flush();??
  21. ????}??
  22. }??

?

需要注意的方面是,需要使用PrintWriter的println而不是write方法,否则服务器端会读不到数据的。原因就是println会在输出的时候在字符串后面加一个换行符,而write不会。
Println和write具体区别可以参考如下网址,里面的网友有讨论:
http://www.oschina.net/question/101123_17855

?

4.JSP中显示中文的乱码。
有的时候JSP页面在显示中文的时候会有乱码,大多数情况就是字符集配置和页面编码的问题。只要保证如下的几个配置没有问题,一般就不会有乱码出现。
a.JSP页面顶端添加如下语句:

Java代码??Java中的乱码有关问题
  1. <%@?page?contentType="text/html;?charset=utf-8"?language="java"?errorPage=""?%>??

?

b.在HTML的head标签中添加如下语句。

Java代码??Java中的乱码有关问题
  1. <meta?http-equiv="Content-Type"?content="text/html;?charset=utf-8"?/>??

?

c.保证JSP的页面编码与上面两个的charset相同,这点我有在文章的第一点说过。

上面的字符集可以根据需要自己灵活选择,不一定非要utf-8。不过因为utf-8对各国语言,特别是中文支持较好,所以推荐使用。我就曾经遇到过滘在GB2312编码的页面无法正常显示的问题。
?
5.Post和Get传递中文,后台获取乱码。
前台传递中文也分为Get和Post方法。


a.Get方法的情况:
Get方法的时候主要是URL传递中文。
如果是在js文件中,可以使用如下代码进行中文转码。

Js代码??Java中的乱码有关问题
  1. var?url?="http://www.baidu.com/s?industry=编码"??
  2. url?=?encodeURI(url);??

?

如果是在jsp文件中,则可以使用如下语句进行转码。
页面开始引入:

Java代码??Java中的乱码有关问题
  1. <%@?page?import="java.net.URLEncoder"?%>??

?

??????需要转码的地方使用URLEncoder进行编码:

Js代码??Java中的乱码有关问题
  1. <a?href="xxxxx.xx?industry=<%=URLEncoder.encode("http://www.baidu.com/s?wd=编码",?"UTF-8")%>">??

?

无论使用哪种方法,在后台获取中文的时候都要使用如下代码:

Java代码??Java中的乱码有关问题
  1. request.setCharacterEncoding("utf-8");??
  2. String?industry?=?new?String(??
  3. request.getParameter("industry?").getBytes("ISO8859-1"),"UTF-8");????

【注】
1.对于request,是指提交内容的编码,指定后可以通过getParameter()则直接获得正确的字符串,如果不指定,则默认使用iso8859-1编码,为了统一,需要提交指定传输编码。
2.上面代码的第二句好像和第2条中给出的公式矛盾。我也纠结了好久,最后发现ISO8859-1是一种比较老的编码,通常叫做Latin-1,属于单字节编码,正好和计算机最基础的表示单位一致,因此使用它进行转码一般也没有问题。
iso-8859-1是JAVA网络传输使用的标准字符集,而gb2312是标准中文字符集,当你作出提交表单等需要网络传输的操作的时候,就需要把 iso-8859-1转换为gb2312字符集显示,否则如果按浏览器的gb2312格式来解释iso-8859-1字符集的话,由于2者不兼容,所以会是乱码。为了省事,建议统一使用utf-8字符集。
b.POST方法的情况。?
对于Post的情况就比较简单了,只需要在post的函数调用部分,制定post的header的字符集,如:

Js代码??Java中的乱码有关问题
  1. xmlHttp.open("post",?url?,?true);??
  2. xmlHttp.setRequestHeader("Content-Type","text/xml;?charset=?utf-8");???
  3. xmlHttp.send(param);??

?

其中param为要传递的参数。

后台部分和get方法一样,设置如下即可,注意传输和接受的字符集要统一。

没懂的话可以参考如下文章,写的挺好。
http://www.cnblogs.com/qiuyi21/articles/1089555.html

6.后台向前台传递中文乱码。
在这里提供一个函数,通过这个函数来发送信息,就不会出现乱码,核心思想也是设置response流的字符集。函数代码如下:

Java代码??Java中的乱码有关问题
  1. /**?
  2. ?*?@Function:writeResponse?
  3. ?*?@Description:ajax方式返回字符串?
  4. ?*?@param?str:json?
  5. ?*?@return:true:输出成功,false:输出失败?
  6. ?*/??
  7. public?boolean?writeResponse(String?str){??
  8. ????boolean?ret?=?true;??
  9. ????try{??
  10. ????????HttpServletResponse?response?=?ServletActionContext.getResponse();??
  11. ????????response.setContentType("text/html;charset=utf-8");??
  12. ????????PrintWriter?pw?=?response.getWriter();??
  13. ????????pw.print(str);??
  14. ????????pw.close();??
  15. ????}catch?(Exception?e)?{??
  16. ????????ret?=?false;??
  17. ????????e.printStackTrace();??
  18. ????}??
  19. ????return?ret;??
  20. }?????

?

7.下载文件时文件名乱码。
下过下载的人都知道下载的文件容易出现乱码,原因也是没有对输出流的编码格式进行限定。

附上一段代码,用来帮你完成无乱码下载。

Java代码??Java中的乱码有关问题
  1. HttpServletResponse?response?=?ServletActionContext.getResponse();??
  2. response.setContentType("text/html;charset=utf-8");??
  3. response.reset();??
  4. String?header?=?"attachment;?filename="?+?picName;??
  5. ??????header?=?new?String(header.getBytes(),?"UTF-8");??
  6. ??????response.setHeader("Content-disposition",?header);??

核心代码就上几句,注意第二句和第三句的reset的顺序不能搞错。
reset的作用是用来清空buffer缓存的,清空请求前部的一些空白行。

?

以上只是做了比较简单的总结,具体乱码有的时候可能是多个情况的组合,具体问题具体分析。如果错误欢迎指正。

转载自:http://aspnetdb.iteye.com/blog/1162774

热点排行