首頁 > Java > java教程 > Java中亂碼問題的解決方法分享

Java中亂碼問題的解決方法分享

黄舟
發布: 2017-07-20 14:13:16
原創
1585 人瀏覽過

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編碼才能相互轉換

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); 
  } 
}
登入後複製

輸出結果為:

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了。

測試範例如下:

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")); 
  } 
}
登入後複製

輸出結果為:

1.中文  
2.����  
3.**************************  
4.中文  
5.涓枃
登入後複製

#可以看出,使用哪種字元集編碼一個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不會。 

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(" rel="external nofollow" 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方法一样,设置如下即可,注意传输和接受的字符集要统一。

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.下载文件时文件名乱码。

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

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

Java代码

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缓存的,清空请求前部的一些空白行。 

以上是Java中亂碼問題的解決方法分享的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板