ホームページ  >  記事  >  Java  >  Java でのコード化けの問題に対する解決策の共有

Java でのコード化けの問題に対する解決策の共有

黄舟
黄舟オリジナル
2017-07-20 14:13:161529ブラウズ

1. ファイルページのエンコードによる文字化け。

各ファイル (java、js、jsp、html など) には独自のエンコード形式があり、ファイル内のコードは、あるエンコードでは正常に表示されますが、別のエンコードでは文字化けして表示されます。

Eclipse では、各プロジェクトにはエンコード形式 (テキスト ファイル エンコード) があり、通常はデフォルトで GBK になります。より良いプログラミング習慣は、新しいプロジェクトを作成し、最初にプロジェクトのエンコードを UTF-8 に設定することです。

その理由は非常に単純です。UTF-8 には、世界中のすべての国で使用する必要がある文字が含まれており、高い汎用性を持っています。いくつかの一般的な文字セット、GBK、GB2312、および UTF-8 の関係は次のとおりです。

GBK は、国家標準 GB2312 をベースに拡張された後、GB2312 と互換性のある標準です。 GBK、GB2312 などと UTF8 は、Unicode エンコードを通じて相互に変換する必要があります

2. 異なる文字セットの文字列変換によって発生する文字化け。

すべての文字列は、基になる実装のバイト配列に格納されます。異なる文字セットが使用される場合、格納される配列の長さは当然異なります。同じ文字セットを使用してデコードしないと必ず文字化けが発生します。

たとえば、次のコード:

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 エンコードを使用すると、結果のバイト配列の長さが異なります。これは、utf-8 では中国語のエンコードに 3 バイトが使用されるのに対し、GBK では中国語のエンコードに 2 バイトが使用されるためです。私のプロジェクトはデフォルトで UTF-8 を使用するため、パラメータなしで getBytes() を使用して取得される配列の長さは、UTF-8 でエンコードされた文字列の長さと同じになります。文字セットの詳細については、最初の部分に記載されている記事のアドレスを参照してください。

JDK の getBytes メソッドの説明:

getBytes() は、プラットフォームのデフォルトの文字セットを使用してこの String をバイト シーケンスにエンコードし、結果を新しいバイト配列に格納します。

getBytes(Charset charset) 指定された文字セットを使用してこの文字列をバイト シーケンスにエンコードし、結果を新しいバイト配列に格納します。

各文字列の下部には独自のエンコード方法があります。ただし、getByte メソッドを呼び出すと、取得されるバイト配列は特定の文字セットを使用してエンコードされた配列となるため、不要な変換は必要ありません。

上記のバイト配列を取得した後、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 strSource = "你想要转码的字符串"; 
String strSomeEncoding = "utf-8";  //例如utf-8 
String strTarget = new String (strSource.getBytes(Charset.forName(strSomeEncoding)), strSomeEncoding);

JDK の getBytes メソッドの説明:

String(byte[] bytes) プラットフォームのデフォルトの文字セットを使用して、指定されたバイト配列をデコードすることにより、新しい String を構築します。

String(byte[] bytes, Charset charset) 指定された文字セットを使用して指定されたバイト配列をデコードすることにより、新しい String を構築します。

3. ソケットネットワーク送信による中国語の文字化け。

Socket を使用して通信する場合、PrintStream または PrintWriter を使用して送信することができます。英語の送信は問題ありませんが、中国語の送信は文字化けする可能性があります。インターネット上では多くの意見がありますが、実際にテストした結果、問題は依然としてバイトと文字にあることがわかりました。

ご存知のとおり、Java はバイト ストリームと文字ストリームに分かれており、文字 (char) は 16 ビット、バイト (BYTE) は 8 ビットです。 PrintStrean は 8 ビット データの文字列を書き込みます。 PrintWriter は 16 ビット データの文字列を書き込みます。

文字列はデフォルトでは UNICODE (16 ビット) でエンコードされます。したがって、PrintWriter で書かれた文字列はクロスプラットフォームでより優れていますが、PrintStream では文字セットが文字化けする可能性があります。

上記の言葉は次のように理解できます。PrintStream はバイトの操作に使用され、PrintWriter は Unicode の操作に使用されます。PrintStream が一度に 8 ビットを読み取ると、漢字 (1 つの漢字が 16 ビットを占有) に遭遇すると文字化けします。が現れるかもしれません。一般的に中国語を処理する場合はPrintWriterを使用します。

Webサイトの最終テストでは、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(); 
  } 
}

注意すべき点は、write メソッドの代わりに PrintWriter の println を使用する必要があることです。そうしないと、サーバーはデータを読み取ることができません。その理由は、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 ページのエンコーディングが上記の 2 つの文字セットと同じであることを確認します。これについては、記事の最初のポイントで説明しました。

上面的字符集可以根据需要自己灵活选择,不一定非要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 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。