) Java字元編碼轉換

來源:互聯網
上載者:User
JVM
JVM啟動後,JVM會設定一些系統屬性以表明JVM的預設地區。
user.language,user.region,file.encoding等。 可以使用System.getProperties()詳細查看所有的系統屬性。
如在英文作業系統(如UNIX)下,可以使用如下屬性定義強制指定JVM為中文環境 -Dclient.encoding.override=GBK -Dfile.encoding=GBK -Duser.language=zh -Duser.region=CN
.java-->.class編譯
說明:一般javac根據當前os地區設定,自動決定源檔案的編碼.可以通過-encoding強制指定.
錯誤可能:
1 gbk編碼源檔案在英文環境下編譯,javac不能正確轉換.曾見於java/jsp在英文unix下. 檢測方法:寫/u4e00格式的漢字,繞開javac編碼,再在jvm中,將漢字作為int列印,看值是否相等;或直接以UTF-8編碼開啟.class 檔案,看看常量字串是否正確儲存漢字。
檔案讀寫
外部資料如檔案經過讀寫和轉換兩個步驟,轉為jvm所使用字元。InputStream/OutputStream用於讀寫原始外部資料,Reader/Writer執行讀寫和轉換兩個步驟。
1 檔案讀寫轉換由java.io.Reader/Writer執行;輸入輸出資料流 InputStream/OutputStream 處理漢字不合適,應該首選使用Reader/Writer,如 FileReader/FileWriter。
2 FileReader/FileWriter使用JVM當前編碼讀寫檔案.如果有其它編碼格式,使用InputStreamReader/OutputStreamWriter
3 PrintStream有點特殊,它自動使用jvm預設編碼進行轉換。
讀取.properties檔案
.propeties 檔案由Properties類以iso8859-1編碼讀取,因此不能在其中直接寫漢字,需要使用JDK 的native2ascii工具轉換漢字為/uXXXX格式。命令列:native2ascii ?encoding GBK inputfile outputfile
讀取XML檔案
1 XML檔案讀寫同於檔案讀寫,但應注意確保XML頭中聲明如<? xml version=”1.0” encoding=”gb2312” ?>與檔案編碼保持一致。
2 javax.xml.SAXParser類接受InputStream作為輸入參數,對於Reader,需要用org.xml.sax.InputSource封裝一下,再給SAXParser。
3 對於UTF-8編碼 XML,注意防止編輯器自動加上/uFFFE BOM頭, xml parser會報告content is not allowed in prolog。
位元組數組
1 使用 new String(byteArray,encoding) 和 String.getBytes(encoding) 在位元組數組和字串之間進行轉換
也可以用ByteArrayInputStream/ByteArrayOutputStream轉為流後再用InputStreamReader/OutputStreamWriter轉換。
錯誤編碼的字串(iso8859-1轉碼gbk)
如果我們得到的字串是由錯誤的轉碼方式產生的,例如:對於gbk中文,由iso8859-1方式轉換,此時如果用調試器看到的字串一般是 的樣子,長度一般為文本的位元組長度,而非漢字個數。
可以採用如下方式轉為正確的中文:
text = new String( text.getBytes(“iso8859-1”),”gbk”);

WEB/Servlet/JSP
1 對於JSP,確定頭部加上 <%@ page contentType="text/html;charset=gb2312"%>這樣的標籤。
2 對於Servlet,確定 設定setContentType (“text/html; charset=gb2312”),以上兩條用於使得輸出漢字沒有問題。
3 為輸出HTML head中加一個 <meta http-equiv="Content-Type" content="text/html; charset=gb2312"> ,讓瀏覽器正確確定HTML編碼。
4 為Web應用加一個Filter,確保每個Request明確調用setCharacterEncoding方法,讓輸入漢字能夠正確解析。
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.UnavailableException;
import javax.servlet.http.HttpServletRequest;
/**
* Example filter that sets the character encoding to be used in parsing the
* incoming request
*/
public class SetCharacterEncodingFilter
implements Filter {
public SetCharacterEncodingFilter()
{}
protected boolean debug = false;
protected String encoding = null;
protected FilterConfig filterConfig = null;
public void destroy() {
this.encoding = null;
this.filterConfig = null;
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// if (request.getCharacterEncoding() == null)
// {
// String encoding = getEncoding();
// if (encoding != null)
// request.setCharacterEncoding(encoding);
//
// }
request.setCharacterEncoding(encoding);
if ( debug ){
System.out.println( ((HttpServletRequest)request).getRequestURI()+"setted to "+encoding );
}
chain.doFilter(request, response);
}
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
this.encoding = filterConfig.getInitParameter("encoding");
this.debug = "true".equalsIgnoreCase( filterConfig.getInitParameter("debug") );
}
protected String getEncoding() {
return (this.encoding);
}
}
web.xml中加入:
<filter>
<filter-name>LocalEncodingFilter</filter-name>
<display-name>LocalEncodingFilter</display-name>
<filter-class>com.ccb.ectipmanager.request.SetCharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>gb2312</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>false</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>LocalEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
5 用於Weblogic(vedor-specific):
其一:在web.xml裡加上如下指令碼:
<context-param>
<param-name>weblogic.httpd.inputCharset./*</param-name>
<param-value>GBK</param-value>
</context-param>
其二(可選)在weblogic.xml裡加上如下指令碼:
<charset-params>
<input-charset>
<resource-path>/*</resource-path>
<java-charset-name>GBK</java-charset-name>
</input-charset>
</charset-params>
SWING/AWT/SWT
對 於SWING/AWT,Java會有些預設字型如Dialog/San Serif,這些字型到系統真實字型的映射在$JRE_HOME/lib/font.properties.XXX檔案中指定。排除字型顯示問題時,首先 需要確定JVM的地區為zh_CN,這樣font.properties.zh_CN檔案才會發生作用。對於 font.properties.zh_CN , 需要檢查是否映射預設字型到中文字型如宋體。
在Swing中,Java自行解釋TTF字型,渲染顯示;對於AWT,SWT顯示部分交由作業系統。首先需要確定系統裝有中文字型。
1 漢字顯示為”□”,一般為顯示字型沒有使用中文字型,因為Java對於當前字型顯示不了的字元,不會像Windows一樣再採用預設字型顯示。
2 部分不常見漢字不能顯示,一般為顯示字型檔中漢字不全,可以換另外的中文字型試試。
3 對於AWT/SWT,首先確定JVM運行環境的地區設定為中文,因為此處設計JVM與作業系統api調用的轉換問題,再檢查其它問題。
JNI
JNI中jstring以UTF-8編碼給我們,需要我們自行轉為本地編碼。對於Windows,可以採用WideCharToMultiByte/MultiByteToWideChar函數進行轉換,對於Unix,可以採用iconv庫。
這裡從SUN jdk 1.4 原始碼中找到一段使用jvm String 對象的getBytes的轉換方式,相對簡單和跨平台,不需要第三方庫,但速度稍慢。函數原型如下:
/* Convert between Java strings and i18n C strings */
JNIEXPORT jstring
NewStringPlatform(JNIEnv *env, const char *str);
JNIEXPORT const char *
GetStringPlatformChars(JNIEnv *env, jstring jstr, jboolean *isCopy);
JNIEXPORT jstring JNICALL
JNU_NewStringPlatform(JNIEnv *env, const char *str);
JNIEXPORT const char * JNICALL
JNU_GetStringPlatformChars(JNIEnv *env, jstring jstr, jboolean *isCopy);
JNIEXPORT void JNICALL
JNU_ReleaseStringPlatformChars(JNIEnv *env, jstring jstr, const char *str);
附件jni_util.h,jni_util.c
JDK1.4/1.5新增部分
字元集相關類(Charset/CharsetEncoder/CharsetDecoder)
jdk1.4開始,對字元集的支援在java.nio.charset包中實現。
常用功能:
1 列出jvm所支援字元集:Charset.availableCharsets()
2 能否對看某個Unicode字元編碼,CharsetEncoder.canEncode()
常見問題
在JVM下,用System.out.println不能正確列印中文,顯示為???
System.out.println是PrintStream,它採用jvm預設字元集進行轉碼工作,如果jvm的預設字元集為iso8859-1,則中文顯示會有問題。此問題常見於Unix下,jvm的地區沒有明確指定的情況。
在英文UNIX環境下,用System.out.println能夠正確列印漢字,但是內部處理錯誤
可能是漢字在輸入轉換時,就沒有正確轉碼:
即gbk文本à(iso8859-1轉碼)àjvm char(iso8859-1編碼漢字)à (iso8859-1轉碼)à輸出。
gbk漢字經過兩次錯誤轉碼,原封不動的被傳遞到輸出,但是在jvm中,並未以正確的unicode編碼錶示,而是以一個漢字位元組一個char的方式表示,從而導致此類錯誤。
GB2312-80,GBK,GB18030-2000 漢字字元集
GB2312-80 是在國內電腦漢字資訊技術發展初始階段制定的,其中包含了大部分常用的一、二級漢字,和 9 區的符號。該字元集是幾乎所有的中文系統和國際化的軟體都支援的中文字元集,這也是最基本的中文字元集。其編碼範圍是高位0xa1-0xfe,低位也是 0xa1-0xfe;漢字從 0xb0a1 開始,結束於 0xf7fe;
GBK 是 GB2312-80 的擴充,是向上相容的。它包含了 20902 個漢字,其編碼範圍是 0x8140-0xfefe,剔除高位 0x80 的字位。其所有字元都可以一對一映射到 Unicode 2.0,也就是說 JAVA 實際上提供了 GBK 字元集的支援。這是現階段 Windows 和其它一些中文作業系統的預設字元集,但並不是所有的國際化軟體都支援該字元集,感覺是他們並不完全知道 GBK 是怎麼回事。值得注意的是它不是國家標準,而只是規範。隨著 GB18030-2000國標的發布,它將在不久的將來完成它的曆史使命。
GB18030-2000(GBK2K) 在 GBK 的基礎上進一步擴充了漢字,增加了藏、蒙等少數民族的字形。GBK2K 從根本上解決了字位不夠,字形不足的問題。它有幾個特點,
它並沒有確定所有的字形,只是規定了編碼範圍,留待以後擴充。
編碼是變長的,其二位元組部分與 GBK 相容;四位元組部分是擴充的字形、字位,其編碼範圍是首位元組 0x81-0xfe、二位元組0x30-0x39、三位元組 0x81-0xfe、四位元組0x30-0x39。
UTF-8/UTF-16/UTF-32
UTF,即Unicode Transformer Format,是Unicode代碼點(code point)的實際表示方式,按其基本長度所用位元分為UTF-8/16/32。它也可以認為是一種特殊的外部資料編碼,但能夠與Unicode代碼點做一一對應。
UTF-8是變長編碼,每個Unicode代碼點按照不同範圍,可以有1-3位元組的不同長度。
UTF-16長度相對固定,只要不處理大於/U200000範圍的字元,每個Unicode代碼點使用16位即2位元組表示,超出部分使用兩個UTF-16即4位元組表示。按照高低位位元組順序,又分為UTF-16BE/UTF-16LE。
UTF-32長度始終固定,每個Unicode代碼點使用32位即4位元組表示。按照高低位位元組順序,又分為UTF-32BE/UTF-32LE。
UTF 編碼有個優點,即儘管編碼位元組數不等,但是不像gb2312/gbk編碼一樣,需要從文本開始尋找,才能正確對漢字進行定位。在UTF編碼下,根據相對固 定的演算法,從當前位置就能夠知道當前位元組是否是一個代碼點的開始還是結束,從而相對簡單的進行字元定位。不過定位問題最簡單的還是UTF-32,它根本不 需要進行字元定位,但是相對的大小也增加不少。
關於GCJ JVM
GCJ並未完全依照sun jdk的做法,對於地區和編碼問題考慮尚不夠周全。GCJ啟動時,地區始終設為en_US,編碼也預設為iso8859-1。但是可以用Reader/Writer做正確編碼轉換

內容來源自:http://blog.csdn.net/yuanyuan110_l/archive/2008/01/21/2057658.aspx

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.