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数组存储,使用不同的字符集,存储的数组长度当然就不同。如果不使用同一种字符集进行解码,就一定会出现乱码。
例如如下代码:
- import java.io.UnsupportedEncodingException;
- import java.nio.charset.Charset;
- public class TestCharset {
- public static void main(String[] args) throws UnsupportedEncodingException {
- String strChineseString = "中文";
- String encoding = System.getProperty("file.encoding");
- System.out.println("系统默认的字符集是:" + encoding);
- System.out.println(strChineseString.getBytes(Charset.forName("GBK")).length);
- System.out.println(strChineseString.getBytes(Charset.forName("UTF-8")).length);
- System.out.println(strChineseString.getBytes().length);
- }
- }
输出结果为:
- 系统默认的字符集是:UTF-8
- 4
- 6
- 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了。
测试例子如下:
- import java.io.UnsupportedEncodingException;
- import java.nio.charset.Charset;
- public class TestCharset {
- public static void main(String[] args) throws UnsupportedEncodingException {
- String strChineseString = "中文";
- byte[] byteGBK = null;
- byte[] byteUTF8 = null;
- byteGBK = strChineseString.getBytes(Charset.forName("GBK"));
- byteUTF8 = strChineseString.getBytes(Charset.forName("utf-8"));
- System.out.println(new String(byteGBK,"GBK"));
- System.out.println(new String(byteGBK,"utf-8"));
- System.out.println("**************************");
- System.out.println(new String(byteUTF8,"utf-8"));
- System.out.println(new String(byteUTF8,"GBK"));
- }
- }
输出结果为:
- 中文
- ����
- **************************
- 中文
- 涓枃
可以看出,使用哪种字符集编码一个String,在生成一个String的时候就必须使用相应的编码,否则就会出现乱码。
简单来讲,只有满足如下公式的String转码,才不会乱码。
- String strSource = "你想要转码的字符串";
- String strSomeEncoding = "utf-8"; //例如utf-8
- 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没有出现乱码。代码如下:
- import java.io.BufferedReader;
- import java.io.DataOutputStream;
- import java.io.IOException;
- import java.io.OutputStreamWriter;
- import java.io.PrintWriter;
- import java.net.Socket;
- public class TestSocket {
- public static void main(String[] args) throws IOException {
- Socket socket = new Socket();
- DataOutputStream dos = null;
- PrintWriter pw = null;
- BufferedReader in = null;
- String responseXml = "要传输的中文";
- //..........
- dos = new DataOutputStream(socket.getOutputStream());
- pw = new PrintWriter(new OutputStreamWriter(dos)); //不带自动刷新的Writer
- pw.println(responseXml);
- pw.flush();
- }
- }
需要注意的方面是,需要使用PrintWriter的println而不是write方法,否则服务器端会读不到数据的。原因就是println会在输出的时候在字符串后面加一个换行符,而write不会。
Println和write具体区别可以参考如下网址,里面的网友有讨论:
http://www.oschina.net/question/101123_17855
4.JSP中显示中文的乱码。
有的时候JSP页面在显示中文的时候会有乱码,大多数情况就是字符集配置和页面编码的问题。只要保证如下的几个配置没有问题,一般就不会有乱码出现。
a.JSP页面顶端添加如下语句:
- <%@ page contentType="text/html; charset=utf-8" language="java" errorPage="" %>
b.在HTML的head标签中添加如下语句。
- <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文件中,可以使用如下代码进行中文转码。
- var url ="http://www.baidu.com/s?industry=编码"
- url = encodeURI(url);
如果是在jsp文件中,则可以使用如下语句进行转码。
页面开始引入:
- <%@ page import="java.net.URLEncoder" %>
需要转码的地方使用URLEncoder进行编码:
- <a href="xxxxx.xx?industry=<%=URLEncoder.encode("http://www.baidu.com/s?wd=编码", "UTF-8")%>">
无论使用哪种方法,在后台获取中文的时候都要使用如下代码:
- request.setCharacterEncoding("utf-8");
- String industry = new String(
- 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的字符集,如:
- xmlHttp.open("post", url , true);
- xmlHttp.setRequestHeader("Content-Type","text/xml; charset= utf-8");
- xmlHttp.send(param);
其中param为要传递的参数。
后台部分和get方法一样,设置如下即可,注意传输和接受的字符集要统一。
没懂的话可以参考如下文章,写的挺好。
http://www.cnblogs.com/qiuyi21/articles/1089555.html
6.后台向前台传递中文乱码。
在这里提供一个函数,通过这个函数来发送信息,就不会出现乱码,核心思想也是设置response流的字符集。函数代码如下:
- /**
- * @Function:writeResponse
- * @Description:ajax方式返回字符串
- * @param str:json
- * @return:true:输出成功,false:输出失败
- */
- public boolean writeResponse(String str){
- boolean ret = true;
- try{
- HttpServletResponse response = ServletActionContext.getResponse();
- response.setContentType("text/html;charset=utf-8");
- PrintWriter pw = response.getWriter();
- pw.print(str);
- pw.close();
- }catch (Exception e) {
- ret = false;
- e.printStackTrace();
- }
- return ret;
- }
7.下载文件时文件名乱码。
下过下载的人都知道下载的文件容易出现乱码,原因也是没有对输出流的编码格式进行限定。
附上一段代码,用来帮你完成无乱码下载。
- HttpServletResponse response = ServletActionContext.getResponse();
- response.setContentType("text/html;charset=utf-8");
- response.reset();
- String header = "attachment; filename=" + picName;
- header = new String(header.getBytes(), "UTF-8");
- response.setHeader("Content-disposition", header);
核心代码就上几句,注意第二句和第三句的reset的顺序不能搞错。
reset的作用是用来清空buffer缓存的,清空请求前部的一些空白行。
以上只是做了比较简单的总结,具体乱码有的时候可能是多个情况的组合,具体问题具体分析。如果错误欢迎指正。
8:String(byte[] bytes, Charset charset) 和 getBytes() 使用
@Test public void testBytes(){ //字节数 //中文:ISO:1 GBK:2 UTF-8:3 //数字或字母: ISO:1 GBK:1 UTF-8:1 String username = "中"; try { //得到指定编码的字节数组 字符串--->字节数组 byte[] u_iso=username.getBytes("ISO8859-1"); byte[] u_gbk=username.getBytes("GBK"); byte[] u_utf8=username.getBytes("utf-8"); System.out.println(u_iso.length); System.out.println(u_gbk.length); System.out.println(u_utf8.length); //跟上面刚好是逆向的,字节数组---->字符串 String un_iso=new String(u_iso, "ISO8859-1"); String un_gbk=new String(u_gbk, "GBK"); String un_utf8=new String(u_utf8, "utf-8"); System.out.println(un_iso); System.out.println(un_gbk); System.out.println(un_utf8); //有时候必须是iso字符编码类型,那处理方式如下 String un_utf8_iso=new String(u_utf8, "ISO8859-1"); //将iso编码的字符串进行还原 String un_iso_utf8=new String(un_utf8_iso.getBytes("ISO8859-1"),"UTF-8"); System.out.println(un_iso_utf8); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
测试结果:
1
2
3
?
中
中
ä¸
中
乱码原因:为什么使用ISO8859-1编码再组合之后,无法还原"中"字呢,其实原因很简单,因为ISO8859-1编码的编码表中,根本就没有包含汉字字符,当然也就无法通过"中".getBytes("ISO8859-1");来得到正确的"中"字在ISO8859-1中的编码值了,所以再通过new String()来还原就无从谈起了.
有时候,为了让中文字符适应某些特殊要求(如http header头要求其内容必须为iso8859-1编码),可能会通过将中文字符按照字节方式来编码的情况,如:
String s_iso88591 = new String("中".getBytes("UTF-8"),"ISO8859-1"),这样得到的s_iso8859-1字符串实际是三个在ISO8859-1中的字符,在将这些字符传递到目的地后,目的地程序再通过相反的方式String s_utf8 = new String(s_iso88591.getBytes("ISO8859-1"),"UTF-8")来得到正确的中文汉字"中".这样就既保证了遵守协议规定、也支持中文.
相关推荐
Java 中文乱码问题是一个老生常谈的问题,特别是在 Web 应用中。今天,我们将从编码角度分析 Java 编译后在控制台和 Web 等终端显示乱码问题。 一、 Java 处理字符的原理 Java 使用 UNICODE 来存储字符数据,处理...
在Java编程中,中文乱码问题是一个常见的困扰开发者的问题,特别是在处理输入输出或者网络通信时。这个问题涉及到字符编码的理解和正确使用。以下是对这个主题的详细解析: 首先,我们需要了解字符编码的基础知识。...
### Java中文乱码问题详解 #### 一、中文问题的来源与背景 计算机技术发展初期,操作系统主要支持单字节的ASCII字符集。随着全球化进程加快和技术进步,为支持多种语言,尤其是双字节编码的语言(如中文),提出了...
Java中文乱码问题是Java开发中常见的问题,尤其是在Web开发中,乱码问题会导致页面显示混乱,影响用户体验。解决乱码问题需要了解编码的基本原理和各种编码格式的区别。 编码的原因可以总结为两点:计算机中存储...
"java中文乱码问题处理方案" java 中文乱码问题处理方案是 java 开发者经常遇到的问题之一。这个问题的存在是由于 java 系统的中文问题原理没有被正确地理解和解决。只有当我们了解了 java 系统的中文问题原理,...
针对客户端和服务器端传输数据,客户端显示中文字符编码,及应用程序与数据库之间的数据交互等问题,分析了Java乱码产生的原因,并针对每种情况,结合实际的项目开发经验,给出了设置页面编码方式、修改Web服务器...
JAVA 中文乱码问题是开发过程中常见的问题之一,解决这个问题需要了解乱码产生的原因,然后对症下药。下面我们对容易产生乱码问题的场景进行分析,并提出解决方案。 1. 以 POST 方法提交的表单数据中有中文字符 在...
在Java开发过程中,中文乱码问题是开发者经常遇到的问题之一。特别是在处理不同编码格式的数据时,如从数据库读取数据、读写文件或者在网络传输过程中,很容易出现中文乱码的情况。本文将详细探讨Java中的字符编码...
Java中的中文乱码问题主要源于Unicode编码与操作系统或应用程序中使用的其他编码格式之间的转换不匹配。在Java程序设计中,由于Java源文件通常使用Unicode(UTF-8)编码,而操作系统、文本编辑器、浏览器或其他应用...
Java 解决中文乱码问题 Java 中文乱码问题是中国程序员无法避免的话题。乱码的出现是由于中文和英文的编码格式不同,解码也是不一样的。如果中国的程序员不会遇到乱码,那么只有使用汉语编程。Han语编程是怎么回事...
Java中文乱码问题是编程者在开发Java应用程序时经常遇到的问题,尤其是涉及到中文字符处理时。这些问题产生的根本原因在于Java内部采用UNICODE编码,而不同的操作系统和浏览器可能支持不同的编码格式,如Windows中文...
在C++和Java之间进行数据交换时,常常会遇到中文乱码的问题,这主要是由于编码格式不一致导致的。文章《关于C++与Java中文乱码问题分析与解决》深入探讨了这一问题,并提供了一个解决方案。该解决方案涉及到使用`...
Java 中文乱码问题是一个常见的编程困扰,尤其对于处理中文字符的Java程序而言。这个问题通常源于字符编码的不一致,即不同环节采用的字符编码标准不统一。本文将深入探讨这一问题,并提供相应的解决方案。 首先,...
java编码中的中文问题是一个老生常谈的问题了,每次遇到中文乱码LZ要么是按照以前的经验修改,要么则是baidu.com来解决问题。阅读许多关于中文乱码的解决办法的博文后,发现对于该问题我们都(更加包括我自己)没有...
在Linux操作系统中,Java应用程序处理中文字符时可能会遇到乱码问题。这主要涉及到编码格式的不匹配,因为Linux系统默认采用UTF-8编码,而某些Java应用或文件可能使用了GB2312、GBK或其他编码。本篇将详细介绍如何...
在Java编程中,乱码问题是一个常见的困扰,尤其是在处理字符编码时。以下是一些关键的知识点,可以帮助理解和解决Java中的乱码问题。 首先,我们需要理解字符编码的基本概念。字符编码是用来表示文本的一种方式,...
在Java开发中,遇到中文乱码问题是一种常见的挑战,特别是在处理URL时。URL中文乱码问题主要是由于URL编码和解码过程中的不一致导致的。下面将详细介绍如何解决这个问题,并探讨几种常用的方法。 首先,我们需要...
Java编程中的中文问题源于计算机早期对单字节字符编码的依赖,...总的来说,理解Java中的中文问题涉及到对Unicode、系统编码、文件编码以及网络传输编码的深刻认识,通过合理设置和转换编码,可以有效避免乱码问题。