#
Java編程技術中漢字問題的分析及解決
在基于
Java 語言的編程中,我們經(jīng)常碰到
漢字的
處理及顯示的問題。一大堆看不懂的亂碼肯定不是我們愿意看到的顯示效果,怎樣才能夠讓那些漢字正確顯示呢?Java語言默認的編碼方式是UNICODE,
而我們中國人通常使用的文件和數(shù)據(jù)庫都是基于GB2312或者BIG5等方式編碼的,怎樣才能夠恰當?shù)剡x擇漢字編碼方式并正確地處理漢字的編碼呢?本文將
從漢字編碼的常識入手,結合Java編程實例,分析以上兩個問題并提出解決它們的方案。
現(xiàn)在 Java
編程語言已經(jīng)廣泛應用于互聯(lián)網(wǎng)世界,早在 Sun 公司開發(fā) Java 語言的時候,就已經(jīng)考慮到對非英文字符的支持了。Sun 公司公布的 Java
運行環(huán)境(JRE)本身就分英文版和國際版,但只有國際版才支持非英文字符。不過在 Java 編程語言的應用中,對中文字符的支持并非如同 Java
Soft
的標準規(guī)范中所宣稱的那樣完美,因為中文字符集不只一個,而且不同的操作系統(tǒng)對中文字符的支持也不盡相同,所以會有許多和漢字編碼處理有關的問題在我們進
行應用開發(fā)中困擾著我們。有很多關于這些問題的解答,但都比較瑣碎,并不能夠滿足大家迫切解決問題的愿望,關于 Java
中文問題的系統(tǒng)研究并不多,本文從漢字編碼常識出發(fā),分析 Java 中文問題,希望對大家解決這個問題有所幫助。
漢字編碼的常識
我們知道,英文字符一般是以一個字節(jié)來表示的,最常用的編碼方法是 ASCII
。但一個字節(jié)最多只能區(qū)分256個字符,而漢字成千上萬,所以現(xiàn)在都以雙字節(jié)來表示漢字,為了能夠與英文字符分開,每個字節(jié)的最高位一定為1,這樣雙字節(jié)
最多可以表示64K格字符。我們經(jīng)常碰到的編碼方式有 GB2312、BIG5、UNICODE
等。關于具體編碼方式的詳細資料,有興趣的讀者可以查閱相關資料。我膚淺談一下和我們關系密切的 GB2312 和 UNICODE。GB2312
碼,中華人民共和國國家標準漢字信息交換用編碼,是一個由中華人民共和國國家標準總局發(fā)布的關于簡化漢字的編碼,通行于中國大陸地區(qū)及新加坡,簡稱國標
碼。兩個字節(jié)中,第一個字節(jié)(高字節(jié))的值為區(qū)號值加32(20H),第二個字節(jié)(低字節(jié))的值為位號值加32(20H),用這兩個值來表示一個漢字的編
碼。UNICODE 碼是微軟提出的解決多國字符問題的多字節(jié)等長編碼,它對英文字符采取前面加“0”字節(jié)的策略實現(xiàn)等長兼容。如 “A” 的
ASCII 碼為0x41,UNICODE 就為0x00,0x41。利用特殊的工具各種編碼之間可以互相轉換。
Java 中文問題的初步認識
我們基于 Java 編程語言進行應用開發(fā)時,不可避免地要處理中文。Java 編程語言默認的編碼方式是
UNICODE,而我們通常使用的數(shù)據(jù)庫及文件都是基于 GB2312 編碼的,我們經(jīng)常碰到這樣的情況:瀏覽基于 JSP
技術的網(wǎng)站看到的是亂碼,文件打開后看到的也是亂碼,被 Java 修改過的數(shù)據(jù)庫的內(nèi)容在別的場合應用時無法繼續(xù)正確地提供信息。
String sEnglish = “apple”;
String sChinese = “蘋果”;
String s = “蘋果 apple ”; |
sEnglish 的長度是5,sChinese的長度是4,而 s 默認的長度是14。對于 sEnglish來說, Java
中的各個類都支持得非常好,肯定能夠正確顯示。但對于 sChinese 和 s 來說,雖然 Java Soft 聲明 Java
的基本類已經(jīng)考慮到對多國字符的支持(默認 UNICODE 編碼),但是如果操作系統(tǒng)的默認編碼不是 UNICODE ,而是國標碼等。從 Java
源代碼到得到正確的結果,要經(jīng)過 “Java 源代碼-> Java 字節(jié)碼->
;虛擬機->操作系統(tǒng)->顯示設備”的過程。在上述過程中的每一步驟,我們都必須正確地處理漢字的編碼,才能夠使最終的顯示結果正確。
“ Java 源代碼-> Java 字節(jié)碼”,標準的 Java 編譯器 javac 使用的字符集是系統(tǒng)默認的字符集,比如在中文
Windows 操作系統(tǒng)上就是 GBK ,而在 Linux 操作系統(tǒng)上就是ISO-8859-1,所以大家會發(fā)現(xiàn)在 Linux
操作系統(tǒng)上編譯的類中源文件中的中文字符都出了問題,解決的辦法就是在編譯的時候添加 encoding 參數(shù),這樣才能夠與平臺無關。用法是
javac ?Cencoding GBK。
“ Java 字節(jié)碼->虛擬機->操作系統(tǒng)”, Java 運行環(huán)境 (JRE) 分英文版和國際版,但只有國際版才支持非英文字符。
Java 開發(fā)工具包 (JDK) 肯定支持多國字符,但并非所有的計算機用戶都安裝了 JDK 。很多操作系統(tǒng)及應用軟件為了能夠更好的支持
Java ,都內(nèi)嵌了 JRE 的國際版本,為自己支持多國字符提供了方便。
“操作系統(tǒng)->顯示設備”,對于漢字來說,操作系統(tǒng)必須支持并能夠顯示它。英文操作系統(tǒng)如果不搭配特殊的應用軟件的話,是肯定不能夠顯示中文的。
還有一個問題,就是在 Java 編程過程中,對中文字符進行正確的編碼轉換。例如,向網(wǎng)頁輸出中文字符串的時候,不論你是用
還是用<%=string%>,都必須作 UNICODE 到 GBK 的轉換,或者手動,或者自動。在 JSP 1.0中,可以定義輸出字符集,從而實現(xiàn)內(nèi)碼的自動轉換。用法是
<%@page contentType=”text/html;charset=gb2312” %> |
但是在一些 JSP 版本中并沒有提供對輸出字符集的支持,(例如 JSP 0.92),這就需要手動編碼輸出了,方法非常多。最常用的方法是
String s1 = request.getParameter(“keyword”);
String s2 = new String(s1.getBytes(“ISO-8859-1”),”GBK”); |
getBytes 方法用于將中文字符以“ISO-8859-1”編碼方式轉化成字節(jié)數(shù)組,而“GBK”
是目標編碼方式。我們從以ISO-8859-1方式編碼的數(shù)據(jù)庫中讀出中文字符串 s1 ,經(jīng)過上述轉換過程,在支持 GBK
字符集的操作系統(tǒng)和應用軟件中就能夠正確顯示中文字符串 s2 。
Java 中文問題的表層分析及處理
背景
|
開發(fā)環(huán)境 |
JDK1.15 |
Vcafe2.0 |
JPadPro |
服務器端 |
NT IIS |
Sybase System |
Jconnect(JDBC) |
客戶端 |
IE5.0 |
Pwin98 |
|
.CLASS 文件存放在服務器端,由客戶端的瀏覽器運行 APPLET , APPLET 只起調(diào)入 FRAME 類等主程序的作用。界面包括 Textfield ,TextArea,List,Choice 等。
I.用 JDBC 執(zhí)行 SELECT 語句從服務器端讀取數(shù)據(jù)(中文)后,將數(shù)據(jù)用 APPEND 方法加到 TextArea(TA) ,不能正確顯示。但加到 List 中時,大部分漢字卻可正確顯示。
將數(shù)據(jù)按“ISO-8859-1” 編碼方式轉化為字節(jié)數(shù)組,再按系統(tǒng)缺省編碼方式 (Default Character Encoding) 轉化為 STRING ,即可在 TA 和 List 中正確顯示。
程序段如下:
dbstr2 = results.getString(1);
//After reading the result from DB server,converting it to string.
dbbyte1 = dbstr2.getBytes(“iso-8859-1”);
dbstr1 = new String(dbbyte1); |
在轉換字符串時不采用系統(tǒng)默認編碼方式,而直接采用“ GBK” 或者 “GB2312” ,在 A 和 B 兩種情況下,從數(shù)據(jù)庫取數(shù)據(jù)都沒有問題。
II.處理方式與“取中文”相逆,先將 SQL 語句按系統(tǒng)缺省編碼方式轉化為字節(jié)數(shù)組,再按“ISO-8859-1”編碼方式轉化為 STRING ,最后送去執(zhí)行,則中文信息可正確寫入數(shù)據(jù)庫。
程序段如下:
sqlstmt = tf_input.getText();
//Before sending statement to DB server,converting it to sql statement.
dbbyte1 = sqlstmt.getBytes();
sqlstmt = newString(dbbyte1,”iso-8859-1”);
_stmt = _con.createStatement();
_stmt.executeUpdate(sqlstmt);
…… |
問題:如果客戶機上存在 CLASSPATH 指向 JDK 的 CLASSES.ZIP 時(稱為 A 情況),上述程序代碼可正確執(zhí)行。但是如果客戶機只有瀏覽器,而沒有 JDK 和 CLASSPATH 時(稱為 B 情況),則漢字無法正確轉換。
我們的分析:
1.經(jīng)過測試,在 A 情況下,程序運行時系統(tǒng)的缺省編碼方式為 GBK 或者 GB2312 。在 B 情況下,程序啟動時瀏覽器的 JAVA 控制臺中出現(xiàn)如下錯誤信息:
Can't find resource for sun.awt.windows.awtLocalization_zh_CN
然后系統(tǒng)的缺省編碼方式為“8859-1”。
2.如果在轉換字符串時不采用系統(tǒng)缺省編碼方式,而是直接采用 “GBK” 或“GB2312”,則在 A 情況下程序仍然可正常運行,在 B 情況下,系統(tǒng)出現(xiàn)錯誤:
UnsupportedEncodingException。
3.在客戶機上,把 JDK 的 CLASSES.ZIP 解壓后,放在另一個目錄中, CLASSPATH
只包含該目錄。然后一邊逐步刪除該目錄中的 .CLASS 文件,另一邊運行測試程序,最后發(fā)現(xiàn)在一千多個 CLASS
文件中,只有一個是必不可少的,該文件是:
sun.io.CharToByteDoubleByte.class。
將該文件拷到服務器端和其它的類放在一起,并在程序的開頭 IMPORT 它,在 B 情況下程序仍然無法正常運行。
4.在 A 情況下,如果在 CLASSPTH 中去掉 sun.io.CharToByteDoubleByte.class ,則程序運行時測得默認編碼方式為“8859-1”,否則為 “GBK” 或 “GB2312” 。
如果 JDK 的版本為1.2以上的話,在 B 情況下遇到的問題得到了很好的解決,測試的步驟同上,有興趣的讀者可以嘗試一下。
Java 中文問題的根源分析及解決
在簡體中文 MS Windows 98 + JDK 1.3 下,可以用 System.getProperties() 得到 Java 運行環(huán)境的一些基本屬性,類 PoorChinese 可以幫助我們得到這些屬性。
類 PoorChinese 的源代碼:
public class PoorChinese {}
執(zhí)行 java PoorChinese 后,我們會得到:
系統(tǒng)變量 file.encoding 的值為 GBK ,user.language 的值為 zh , user.region 的值為 CN ,這些系統(tǒng)變量的值決定了系統(tǒng)默認的編碼方式是 GBK 。
在上述系統(tǒng)中,下面的代碼將 GB2312 文件轉換成 Big5 文件,它們能夠幫助我們理解 Java 中漢字編碼的轉化:
import java.io.*;
import java.util.*;
public class gb2big5
{
static int iCharNum=0;
public static void main(String[] args) {
System.out.println("Input GB2312 file, output Big5 file.");
if (args.length!=2)
{
System.err.println("Usage: jview gb2big5 gbfile big5file");
System.exit(1);
String inputString = readInput(args[0]);
writeOutput(inputString,args[1]);
System.out.println("Number of Characters in file: "+iCharNum+".");
}
static void writeOutput(String str, String strOutFile)
{
try
{
FileOutputStream fos = new FileOutputStream(strOutFile);
Writer out = new OutputStreamWriter(fos, "Big5");
out.write(str);
out.close();
}
catch (IOException e)
{
e.printStackTrace();
e.printStackTrace();
}
}
static String readInput(String strInFile)
{
StringBuffer buffer = new StringBuffer();
try
{
FileInputStream fis = new FileInputStream(strInFile);
InputStreamReader isr = new InputStreamReader(fis, "GB2312");
Reader in = new BufferedReader(isr);
int ch;
while ((ch = in.read()) > -1)
{
iCharNum += 1;buffer.append((char)ch);
}
in.close();
return buffer.toString();
}
catch (IOException e)
{
e.printStackTrace();
return null;
}
}
} |
編碼轉化的過程如下:
GB2312------------------>Unicode------------->Big5
執(zhí)行 java gb2big5 gb.txt big5.txt ,如果 gb.txt 的內(nèi)容是“今天星期三”,則得到的文件 big5.txt
中的字符能夠正確顯示;而如果 gb.txt 的內(nèi)容是“情人節(jié)快樂”,則得到的文件 big5.txt
中對應于“節(jié)”和“樂”的字符都是符號“?”(0x3F),可見 sun.io.ByteToCharGB2312 和
sun.io.CharToByteBig5 這兩個基本類并沒有編好。
正如上例一樣, Java
的基本類也可能存在問題。由于國際化的工作并不是在國內(nèi)完成的,所以在這些基本類發(fā)布之前,沒有經(jīng)過嚴格的測試,所以對中文字符的支持并不像 Java
Soft 所聲稱的那樣完美。前不久,我的一位技術上的朋友發(fā)信給我說,他終于找到了 Java Servlet 中文問題的根源。兩周以來,他一直為
Java Servlet
的中文問題所困擾,因為每面對一個含有中文字符的字符串都必須進行強制轉換才能夠得到正確的結果(這好象是大家公認的唯一的解決辦法)。
后來,他確實不想如此繼續(xù)安分下去了,因為這樣的事情確實不應該是高級程序員所要做的工作,他就找出 Servlet
解碼的源代碼進行分析,因為他懷疑問題就出在解碼這部分。經(jīng)過四個小時的奮斗,他終于找到了問題的根源所在。原來他的懷疑是正確的, Servlet
的解碼部分完全沒有考慮雙字節(jié),直接把 %XX 當作一個字符。(原來 Java Soft 也會犯這幺低級的錯誤!)
如果你對這個問題有興趣或者遇到了同樣的煩惱的話,你可以按照他的步驟 對Servlet.jar 進行修改:
找到源代碼 HttpUtils 中的 static private String parseName ,在返回前將
sb(StringBuffer) 復制成 byte bs[] ,然后 return new
String(bs,”GB2312”)。作上述修改后就需要自己解碼了:
HashTable form=HttpUtils .parseQueryString(request.getQueryString())或者
form=HttpUtils.parsePostData(……) |
千萬別忘了編譯后放到 Servlet.jar 里面。
關于 Java 中文問題的總結
Java 編程語言成長于網(wǎng)絡世界,這就要求 Java 對多國字符有很好的支持。 Java
編程語言適應了計算的網(wǎng)絡化的需求,為它能夠在網(wǎng)絡世界迅速成長奠定了堅實的基礎。 Java 的締造者 (Java Soft) 已經(jīng)考慮到
Java
編程語言對多國字符的支持,只是現(xiàn)在的解決方案有很多缺陷在里面,需要我們付諸一些補償性的措施。而世界標準化組織也在努力把人類所有的文字統(tǒng)一在一種編
碼之中,其中一種方案是 ISO10646 ,它用四個字節(jié)來表示一個字符。當然,在這種方案未被采用之前,還是希望 Java Soft
能夠嚴格地測試它的產(chǎn)品,為用戶帶來更多的方便。
附一個用于從數(shù)據(jù)庫和網(wǎng)絡中取出 中文亂碼的處理函數(shù),入?yún)⑹怯袉栴}的字符串,出參是問題已經(jīng)解決了的字符串。
1、vi的基本概念
基本上vi可以分為三種狀態(tài),分別是命令模式(command mode)、插入模式(Insert mode)和底行模式(last line mode),各模式的功能區(qū)分如下:
1) 命令行模式command mode)
控制屏幕光標的移動,字符、字或行的刪除,移動復制某區(qū)段及進入Insert mode下,或者到 last line mode。
2) 插入模式(Insert mode)
只有在Insert mode下,才可以做文字輸入,按「ESC」鍵可回到命令行模式。
3) 底行模式(last line mode)
將文件保存或退出vi,也可以設置編輯環(huán)境,如尋找字符串、列出行號……等。
不過一般我們在使用時把vi簡化成兩個模式,就是將底行模式(last line mode)也算入命令行模式command mode)。
2、vi的基本操作
a) 進入vi
在系統(tǒng)提示符號輸入vi及文件名稱后,就進入vi全屏幕編輯畫面:
$ vi myfile
不過有一點要特別注意,就是您進入vi之后,是處于「命令行模式(command mode)」,您要切換到「插入模式(Insert mode)」才能夠輸入文字。初次使用vi的人都會想先用上下左右鍵移動光標,結果電腦一直嗶嗶叫,把自己氣個半死,所以進入vi后,先不要亂動,轉換到「插入模式(Insert mode)」再說吧!
b) 切換至插入模式(Insert mode)編輯文件
在「命令行模式(command mode)」下按一下字母「i」就可以進入「插入模式(Insert mode)」,這時候你就可以開始輸入文字了。
c) Insert 的切換
您目前處于「插入模式(Insert mode)」,您就只能一直輸入文字,如果您發(fā)現(xiàn)輸錯了字!想用光標鍵往回移動,將該字刪除,就要先按一下「ESC」鍵轉到「命令行模式(command mode)」再刪除文字。
d) 退出vi及保存文件
在「命令行模式(command mode)」下,按一下「:」冒號鍵進入「Last line mode」,例如:
: w filename (輸入 「w filename」將文章以指定的文件名filename保存)
: wq (輸入「wq」,存盤并退出vi)
: q! (輸入q!, 不存盤強制退出vi)
3、命令行模式(command mode)功能鍵
1). 插入模式
按「i」切換進入插入模式「insert mode」,按“i”進入插入模式后是從光標當前位置開始輸入文件;
按「a」進入插入模式后,是從目前光標所在位置的下一個位置開始輸入文字;
按「o」進入插入模式后,是插入新的一行,從行首開始輸入文字。
2). 從插入模式切換為命令行模式
按「ESC」鍵。
3). 移動光標
vi可以直接用鍵盤上的光標來上下左右移動,但正規(guī)的vi是用小寫英文字母「h」、「j」、「k」、「l」,分別控制光標左、下、上、右移一格。
按「ctrl」+「b」:屏幕往“后”移動一頁。
按「ctrl」+「f」:屏幕往“前”移動一頁。
按「ctrl」+「u」:屏幕往“后”移動半頁。
按「ctrl」+「d」:屏幕往“前”移動半頁。
按數(shù)字「0」:移到文章的開頭。
按「G」:移動到文章的最后。
按「$」:移動到光標所在行的“行尾”。
按「^」:移動到光標所在行的“行首”
按「w」:光標跳到下個字的開頭
按「e」:光標跳到下個字的字尾
按「b」:光標回到上個字的開頭
按「#l」:光標移到該行的第#個位置,如:5l,56l。
4). 刪除文字
「x」:每按一次,刪除光標所在位置的“后面”一個字符。
「#x」:例如,「6x」表示刪除光標所在位置的“后面”6個字符。
「X」:大寫的X,每按一次,刪除光標所在位置的“前面”一個字符。
「#X」:例如,「20X」表示刪除光標所在位置的“前面”20個字符。
「dd」:刪除光標所在行。
「#dd」:從光標所在行開始刪除#行
5). 復制
「yw」:將光標所在之處到字尾的字符復制到緩沖區(qū)中。
「#yw」:復制#個字到緩沖區(qū)
「yy」:復制光標所在行到緩沖區(qū)。
「#yy」:例如,「6yy」表示拷貝從光標所在的該行“往下數(shù)”6行文字。
「p」:將緩沖區(qū)內(nèi)的字符貼到光標所在位置。注意:所有與“y”有關的復制命令都必須與“p”配合才能完成復制與粘貼功能。
6). 替換
「r」:替換光標所在處的字符。
「R」:替換光標所到之處的字符,直到按下「ESC」鍵為止。
7). 回復上一次操作
「u」:如果您誤執(zhí)行一個命令,可以馬上按下「u」,回到上一個操作。按多次“u”可以執(zhí)行多次回復。
8). 更改
「cw」:更改光標所在處的字到字尾處
「c#w」:例如,「c3w」表示更改3個字
9). 跳至指定的行
「ctrl」+「g」列出光標所在行的行號。
「#G」:例如,「15G」,表示移動光標至文章的第15行行首。
4、Last line mode下命令簡介
在使用「last line mode」之前,請記住先按「ESC」鍵確定您已經(jīng)處于「command mode」下后,再按「:」冒號即可進入「last line mode」。
A) 列出行號
「set nu」:輸入「set nu」后,會在文件中的每一行前面列出行號。
B) 跳到文件中的某一行
「#」:「#」號表示一個數(shù)字,在冒號后輸入一個數(shù)字,再按回車鍵就會跳到該行了,如輸入數(shù)字15,再回車,就會跳到文章的第15行。
C) 查找字符
「/關鍵字」:先按「/」鍵,再輸入您想尋找的字符,如果第一次找的關鍵字不是您想要的,可以一直按「n」會往后尋找到您要的關鍵字為止。
「?關鍵字」:先按「?」鍵,再輸入您想尋找的字符,如果第一次找的關鍵字不是您想要的,可以一直按「n」會往前尋找到您要的關鍵字為止。
D) 保存文件
「w」:在冒號輸入字母「w」就可以將文件保存起來。
E) 離開vi
「q」:按「q」就是退出,如果無法離開vi,可以在「q」后跟一個「!」強制離開vi。
「qw」:一般建議離開時,搭配「w」一起使用,這樣在退出的時候還可以保存文件。
5、vi命令列表
1、下表列出命令模式下的一些鍵的功能:
h
左移光標一個字符
l
右移光標一個字符
k
光標上移一行
j
光標下移一行
^
光標移動至行首
0
數(shù)字“0”,光標移至文章的開頭
G
光標移至文章的最后
$
光標移動至行尾
Ctrl+f
向前翻屏
Ctrl+b
向后翻屏
Ctrl+d
向前翻半屏
Ctrl+u
向后翻半屏
i
在光標位置前插入字符
a
在光標所在位置的后一個字符開始增加
o
插入新的一行,從行首開始輸入
ESC
從輸入狀態(tài)退至命令狀態(tài)
x
刪除光標后面的字符
#x
刪除光標后的#個字符
X
(大寫X),刪除光標前面的字符
#X
刪除光標前面的#個字符
dd
刪除光標所在的行
#dd
刪除從光標所在行數(shù)的#行
yw
復制光標所在位置的一個字
#yw
復制光標所在位置的#個字
yy
復制光標所在位置的一行
#yy
復制從光標所在行數(shù)的#行
p
粘貼
u
取消操作
cw
更改光標所在位置的一個字
#cw
更改光標所在位置的#個字
2、下表列出行命令模式下的一些指令
w filename
儲存正在編輯的文件為filename
wq filename
儲存正在編輯的文件為filename,并退出vi
q!
放棄所有修改,退出vi
set nu
顯示行號
/或?
查找,在/后輸入要查找的內(nèi)容
n
與/或?一起使用,如果查找的內(nèi)容不是想要找的關鍵字,按n或向后(與/聯(lián)用)或向前(與?聯(lián)用)繼續(xù)查找,直到找到為止。
對于第一次用vi,有幾點注意要提醒一下:
1、用vi打開文件,是處于「命令行模式(command
用什么編輯器可以使xml文件的中文變成UTF-8亂碼
我把g b2312改成UTF-8瀏覽器提示出錯~~~
最簡單的Word應該可以完成轉換,另外UE和Edit++都支持轉換
=======================================================
在寫一個東東,是sqlserver后臺,用utf-8編碼,一直是剛出來還可,一刷新就成亂碼了,以為是sql的原因,一次
把<title></title>里的全刪了,就沒問題了,后來發(fā)現(xiàn),最好把<META
http-equiv=Content-Type content="textHtml;
charset=utf-8">放在title前,不然有些還是會錯!
=======================================================
為每個jsp頁面設置了其編碼格式(utf-8),但傳遞數(shù)據(jù)到另一頁面時依然顯示為亂碼? 首先要需要了解的是web容器默認編碼是iso-
8859-1,一個漢字占用兩個字節(jié),而在utf-8中一個漢字占用三個字節(jié)。所以在數(shù)據(jù)傳遞過程中,必須手動設定容器編碼格式,否則會出現(xiàn)字符位丟失的
情況。即3個字節(jié)變?yōu)閮蓚€字節(jié),自然會變成亂碼。為什么保存到數(shù)據(jù)庫中的數(shù)據(jù)都變成了亂碼? 原理同上,首先要搞清楚使用的數(shù)據(jù)庫默認的編碼格式,比如
mysql默認的字符編碼是ISO-8859-1。所以必須手動修改其默認編碼格式。 清楚了以上問題后,再來看如何解決utf-8的亂碼問題。
1:設置web容器的編碼格式。為你的servlet的doGet或doPost方法開始處加入如下代碼:request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
2:為每個jsp頁面指定其編碼格式。<%@ page pageEncoding="utf-8"%>
3:在連接數(shù)據(jù)庫用的URL后加入:useUnicode=true;characterEncoding=utf-8 如: url="jdbc:mysql:///db1?useUnicode=true;characterEncoding=utf-8",
4:為指定數(shù)據(jù)庫默認編碼格式。在C:\WINDOWS目錄下找到my.ini文件,并在[mysqld]中加入default-character-
set=gbk,重新啟動mysql服務。 至此,亂碼問題全部解決。起初總搞上去不清,為什么要將mysql的默認編碼格式設置為gbk,后來由相關
的資料得知utf-8默認輸入編碼方式為gbk,默認輸出編碼方式為utf-16be。 個人認為,將數(shù)據(jù)進行utf-8進行編碼的目的(即將中文編碼
為%的形式),主要是為了在多層服務間進行數(shù)據(jù)傳輸時,防止發(fā)生字符丟失(如msn)。普通的web程序顯然沒有必要這樣做,只要使用以上方法進行處理,
就可以有效的解決亂碼問題,從而結省存儲空間。如果都像公司的SC系統(tǒng)那樣,將一個漢字編碼為18個字符后,再存儲到數(shù)據(jù)庫中,拋開效率不說,就存儲空間
的浪費就夠人受的,要知道,那是需要銀子地!
========================================================
ASP動態(tài)網(wǎng)頁下UTF-8頁面亂碼的解決方法
為什么在ASP里指定了codepage為65001還經(jīng)常顯示亂碼。才子在這里將這個問題詳細解釋一下,以免很多朋友再走彎路,甚至排斥UTF-8。
如果你還不知道UTF-8是什么東東,那才子建議你先去搜索一下UTF-8的相關資料吧。
UTF-8編碼之所以被越來越多的人接受甚至喜歡,肯定是有道理的,在WEB2.0盛行的今天,在大談多瀏覽器兼容的同時,不得不想到字符編碼不同所造成的亂碼現(xiàn)象同樣需要得到很好的處理..... CHINAZ
在N年以前,IE6以下的所有版本,只要沒有安裝相應的字庫,訪問相關的頁面都是會亂碼的,例如,我是IE5 (Windows2000默認)
的版本,在沒有安裝IE繁體字庫的情況下,訪問任何繁體頁面的網(wǎng)站都是會亂碼的,當然前提是該頁面采用了BIG5的Charset,而UTF-8作為一種
國際編碼就能很好的處理該問題,只要將頁面存為UTF-8編碼格式,再在頁面上將codepage及charset全部定義為utf-8就可以在任何客戶
端瀏覽器中顯示出完全正確的內(nèi)容,完全不會亂碼......
好了,這里以ASP頁面為例,以一個實例來看具體操作吧:
打開新建一個ASP頁面,相信玩ASP的朋友都會留意到,許多下載的源碼里,頁面最上方一般都有一句:
以下為引用的內(nèi)容:
%@LANGUAGE="VBSCRIPT" CODEPAGE="936"% CHINAZ
CHINAZ
前面的language應該不用多說了,vbscript就是ASP默認的腳本語言,其實完全可以不用寫,寫了好像還會影響頁面執(zhí)行效率,在這里我
們先不討論這個問題。后面的codepage就是關鍵了,目的就是告訴瀏覽器,此頁面是何種編碼,936代表是簡體中文,而950代表繁體中
文,65001就是我們今天說的UTF-8編碼了。我們將936改成65001。整句如下: CHINAZ
以下為引用的內(nèi)容:
%@LANGUAGE="VBSCRIPT" CODEPAGE="65001"%
再加上輸出幾個中文字看看能不能正確顯示吧。 CHINAZ
以下為引用的內(nèi)容:
<%
Response.Write "第一次測試UTF-8頁面"
%>
OK,直接點擊“保存”,執(zhí)行這個頁面看看,如果不出意外,大家可能看到顯示出的是 “一尾UTF-8頁”這幾個字,中文有亂碼的現(xiàn)象,什么原因呢?
OK,請大家再點擊最上面的 "文件"
菜單,選擇"另存為",最下面一行有個編碼,默認應該是ANSI的,請大家點下拉框,選擇UTF-8,再點保存,再執(zhí)行試試看,如果不出意外,亂得更厲害
了,呵呵,暈了吧。別急,想想原因,因為我們做的頁面是HTML返回的,以前我們寫HTML時,看到body前面,也就是head里都有一句meta,應
該是這樣的:
以下為引用的內(nèi)容:
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
也就是指定頁面以gb2312編碼返回結果,一定要寫在有返回結果輸出的前面。大家都知道gb2312是簡體中文吧,我們今天說的是UTF-8編碼,我們就將gb2312改成UTF-8吧,全部代碼如下: CHINAZ
以下為引用的內(nèi)容:
<%@LANGUAGE="VBSCRIPT" CODEPAGE="65001"%>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<%
Response.Write "第一次測試UTF-8頁面"
%>
一,文件沒有存為對應的格式,
可能有網(wǎng)友認為將META元標記的解碼方式改一下,就可以實現(xiàn)GB2312轉UTF-8,或者UTF-8轉GB2312,這其實是錯誤的,雖然你把
GB2312編碼的網(wǎng)頁的Meta標記改為了Utf-8,但這樣的操作會讓你發(fā)現(xiàn)網(wǎng)頁出現(xiàn)了亂碼。究其原因你文件編碼格式還是gb2312的,這時你應把
文件存為utf-8,再改meta標記的解碼方式。對于將文件存為utf-8,很多朋友可能會用記事本去操作,我不建議這樣去做,因為用記事本轉換的編碼
而做的網(wǎng)頁會在W3C效驗時出現(xiàn)BOM錯誤,具體如下
Byte-Order Mark found in UTF-8 File. The Unicode Byte-Order Mark
(BOM) in UTF-8 encoded files is known to cause problems for some text
editors and older browsers. You may want to consider avoiding its use
until it is better supported.
你可以用比較新版本的editplus和ultraedit都可以選擇保存為無BOM的utf-8格式。
二,文件缺少必要的標識
檢查Html標記里有沒有如下
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
檢查XML文檔里有沒有
<?xml version="1.0" encoding="utf-8"?>
utf-8或者gb2312,看你文檔的編碼。
如果是ASP動態(tài)頁面,最好加上以下幾句
以下為相關html文檔
<%@ LANGUAGE = "VBScript" CodePage = "65001"%>
CodePage = "65001"中的65001代表是UTF-8編碼的文檔,GB2312編碼的是936
以下為相關vbscript文檔
Session.CodePage=65001
另外網(wǎng)上還有如下的ASP代碼,我沒試過
以下為相關vbscript文檔
Response.Charset="utf-8"
結論:采用UTF-8編碼,除了要將文件另存為UTF-8格式之外,還需要同時指定codepage及charset。
http-equiv顧名思義,相當于http的文件頭作用,它可以向瀏覽器傳回一些有用的信息,以幫助正確和精確地顯示網(wǎng)頁內(nèi)容,與之對應的屬性值為content,content中的內(nèi)容其實就是各個參數(shù)的變量值。
meat標簽的http-equiv屬性語法格式是:<meta http-equiv="參數(shù)" content="參數(shù)變量值"> ;其中http-equiv屬性主要有以下幾種參數(shù):
1、Expires(期限)
說明:可以用于設定網(wǎng)頁的到期時間。一旦網(wǎng)頁過期,必須到服務器上重新傳輸。
用法:<meta http-equiv="expires" content="Wed, 20 Jun 2007 22:33:00 GMT">
注意:必須使用GMT的時間格式。
2、Pragma(cache模式)
說明:禁止瀏覽器穎鏡丶撲慊 幕捍嬤蟹夢室趁婺諶蕁?br>
用法:<meta http-equiv="Pragma" content="no-cache">
注意:這樣設定,訪問者將無法脫機瀏覽。
3、Refresh(刷新)
說明:自動刷新并指向新頁面。
用法:<meta http-equiv="Refresh" content="2;URL=http://www.net.cn/">
注意:其中的2是指停留2秒鐘后自動刷新到URL網(wǎng)址。
4、Set-Cookie(cookie設定)
說明:如果網(wǎng)頁過期,那么存盤的cookie將被刪除。
用法:<meta http-equiv="Set-Cookie" content="cookievalue=xxx;
expires=Wednesday, 20-Jun-2007 22:33:00 GMT; path=/">
注意:必須使用GMT的時間格式。
5、Window-target(顯示窗口的設定)
說明:強制頁面在當前窗口以獨立頁面顯示。
用法:<meta http-equiv="Window-target" content="_top">
注意:用來防止別人在框架里調(diào)用自己的頁面。
6、content-Type(顯示字符集的設定)
說明:設定頁面使用的字符集。
用法:<meta http-equiv="content-Type" content="text/html; charset=gb2312">
7、Pics-label(網(wǎng)頁等級評定)
用法:<meta http-equiv="Pics-label" contect="">網(wǎng)頁等級評定
說明:在IE的internet選項中有一項內(nèi)容設置,可以防止瀏覽一些受限制的網(wǎng)站,而網(wǎng)站的限制級別就是通過meta屬性來設置的。
還有Page_Enter、Page_Exit……
補充:
設定進入頁面時的特殊效果<meta http-equiv="Page-Enter" contect="revealTrans(duration=1.0,transtion= 12)">
設定離開頁面時的特殊效果<meta http-equiv="Page-Exit" contect="revealTrans(duration=1.0,transtion= 12)">
Duration的值為網(wǎng)頁動態(tài)過渡的時間,單位為秒。
Transition是過渡方式,它的值為0到23,分別對應24種過渡方式。如下表:
0 盒狀收縮 1 盒狀放射
2 圓形收縮 3 圓形放射
4 由下往上 5 由上往下
6 從左至右 7 從右至左
8 垂直百葉窗 9 水平百葉窗
10 水平格狀百葉窗 11垂直格狀百葉窗
12 隨意溶解 13從左右兩端向中間展開
14從中間向左右兩端展開 15從上下兩端向中間展開
16從中間向上下兩端展開 17 從右上角向左下角展開
18 從右下角向左上角展開 19 從左上角向右下角展開
20 從左下角向右上角展開 21 水平線狀展開
22 垂直線狀展開 23 隨機產(chǎn)生一種過渡方式
這幾天因為學習到了基于AWT的java 軟件程序設計,所以再用eclipse 的過程中遇到了問題,沒有找到那些可視化組件,找了一段時間,才知道,原來安裝VE 不是象其他的軟件一樣,單擊就可以完成。存在了這樣那樣的問題,呵呵,真是的,再好用的軟件也有麻煩的時候啊,不過在安裝的過程中自己也學習到了很多的東西呢!
書上說要下載一個叫做VE—runtime 的東西,沒事簡單的很呢,只要登陸到這個網(wǎng)站(
http://www.eclipse.org/downloads/,在右邊的小框里可以看見)就可以輕松的完成這項工作,自己也覺得沒什么的,不就下載一個軟件嘛,呵呵!你覺的呢?
書上又說了,你要按照以下的方法做,將VE—runtime 解壓到和JDK,EMF,GMF的一個文件里,如果在對VE—runtime解壓過程中出現(xiàn)了“文件覆蓋”對話框,就選擇“全部為否”按鈕予以關閉,然后找configuration子文件夾,刪除除了“config配置設置”以外的所有文件。
大功告成,呵呵,書啊,就是好東西,它叫你學到了很多的東西呢!可是,呵呵!可是,結果是我失敗了,palette中沒有那些書上說的組件!找啊,有錯就找,網(wǎng)上的資源多的很呢!過程和其它的就不說了,只說找的結論,以及一定能讓你安裝好這個軟件的方法!
結論是:VE 只有和其相應版本的EMF,eclipse-SDK,GMF工作,而JDK的要求是要在1.4.2以及以上的版本。干嗎要配套使用呢,更高版本的不行嘛,不是更好嘛,想了很久還是不知道,也沒有找過,要是有人找到了,請告訴我一聲啊,謝謝了!還有一個結論就是:不要總是相信書上的東西,它也是有錯的時候!
下面說一下安裝的具體過程:
(1)要在以下的網(wǎng)址上下載我們需要的東西(EMF,GMF,VE,eclipse-SDK)http://download.eclipse.org/tools/ve/downloads/drops/R-1.2.3_jem-200701301117/index.html(注意!一定看清其版本)我們下的這幾個的版本分別是:
Eclipse build eclipse-SDK-3.2,EMF build 2.2.0,GEF Build 3.2,VE-runtime-1.2.3如果這一步錯了,下面的工作就不要進行了!
(2)將 Eclipse build eclipse-SDK-3.2直接解壓到某個磁盤中,(如D:盤)這時在D盤根目錄就出現(xiàn)了一個叫eclipse的文件夾,(注意不要先建一個eclipse文件夾,在將Eclipse build eclipse-SDK-3.2解壓到這個文件夾中,這樣會出現(xiàn)兩個eclipse文件夾)打開它有許多的文件,不要管它!
(3)在eclipse 文件夾中建立以如下幾個文件EMF,GEF,VEruntime,VESDK然后將 Eclipse build eclipse-SDK-3.2解壓到VESDK中,將EMF build 2.2.0解壓到EMF中,將GEF Build 3.2解壓GEF中,將VE-runtime-1.2.3解壓到VEruntime中,呵呵!,不要煩啊,這樣做的好處就是能讓你一次安裝完成!
(4)在eclipse中建立一個名為links的文件夾,在其中分別建立如下的文本文件:(可以先將其建為.txt格式的,寫完內(nèi)容后,重命名為.link)
EMF.link 內(nèi)容為:path=D://eclipse//EMF
GEF.link 內(nèi)容為:path=D://eclipse//GEF
VEruntime.link 內(nèi)容為:path=D://eclipse//VEruntime
VESDK.link 內(nèi)容為:path=D://eclipse//VESDK
好了,做到現(xiàn)在啟動eclipse,在新建類快捷鍵中出現(xiàn)了visible class ,在看看palette中是不是出現(xiàn)了需要的可視化組件!如果出現(xiàn)了,祝賀你成功了,如果沒有出現(xiàn),請在安裝一遍,不要恢心,好好看看上邊的過程,你一定會成功的,并體會到java 中可視化的樂趣!