本次對(duì)UUZone
Refactor中一個(gè)大動(dòng)作就是采用UTF-8編碼,由于種種的歷史原因,uuzone一直采用GBK編碼,現(xiàn)在要把這個(gè)編碼轉(zhuǎn)成為UTF-8的。
本文不打算討論技術(shù), 所以簡(jiǎn)單地說(shuō)明這個(gè)工作進(jìn)展的一個(gè)過(guò)程:
** 最早的時(shí)候*,n年前,我們一個(gè)項(xiàng)目需要國(guó)際化支持,毫無(wú)疑問(wèn)utf-8是最佳的編碼選擇,這時(shí)候項(xiàng)目組就遇到了問(wèn) 題:
本地編寫(xiě)的文件中的中文都是GBK編碼的, 僅僅設(shè)置頁(yè)面的contentType="text/html; charset=UTF-8",
出來(lái)的全是亂碼...當(dāng)然拿GBK的東西直接要求對(duì)方用UTF-8看,一定是亂碼.
當(dāng)時(shí)如何解決的過(guò)程已經(jīng)無(wú)法了解, 但最終采用的方案是: 用GBK寫(xiě)文件, 然后采用JDK中的native2ascii工具轉(zhuǎn)換. 問(wèn)題解決了,
但結(jié)果就是多了轉(zhuǎn)碼的過(guò)程, 轉(zhuǎn)碼后的jsp文件人不可讀.
** 做uuzone了*, 項(xiàng)目組建議采用GBK編碼, 因?yàn)槟莻€(gè)轉(zhuǎn)碼工作太繁瑣了,而且導(dǎo)致文件不可讀, 調(diào)試非常麻煩.
于是uuzone就成了GBK的.
由于采用GBK, 遇到了很多相關(guān)的問(wèn)題... 中途至少有2次我"建議"改用UTF-8,
都被評(píng)估認(rèn)為有太多問(wèn)題而沒(méi)有被采納(郁悶的boss啊...)...
** 發(fā)現(xiàn)原來(lái)不需要轉(zhuǎn)碼!* 終于處于某些原因, 我需要自己動(dòng)手來(lái)研究一些技術(shù)細(xì)節(jié),
發(fā)現(xiàn)native2ascii轉(zhuǎn)碼<http://www.uuzone.com/blog/tom/98879.htm>的工作其實(shí)并不需要進(jìn)行.
jsp文件可以直接保存為UTF-8編碼, 輸出的結(jié)果就是UTF-8的...而現(xiàn)在的elips,editplus, ultraedit,
甚至notepad都能保存和識(shí)別utf-8的文件.
** 終于下定決心轉(zhuǎn)為UTF-8.* 既然如此, 就沒(méi)有理由拒絕了. 因此本次refactor項(xiàng)目目標(biāo)之一就是改用UTF-8.
既然文件打算用utf-8保存, 那么就需要批量轉(zhuǎn)換工具...幾下search, 好的工具也找到了.
** 轉(zhuǎn)!* 有工具, 不到20秒, 6000多個(gè)文件就從GBK轉(zhuǎn)成了UTF-8文件格式...
** 問(wèn)題來(lái)了!* 項(xiàng)目中的XML, properties文件是否轉(zhuǎn)碼呢? 本來(lái)計(jì)劃轉(zhuǎn)...但很快發(fā)現(xiàn),這些文件轉(zhuǎn)掉后,
XML,properties文件的讀取都出了不同程度的問(wèn)題...總之項(xiàng)目將根本無(wú)法運(yùn)行...
原因何在?原來(lái)這些UTF-8的文件有一個(gè)所謂BOM<http://www.unicode.org.unicode/faq/utf_bom.html>頭,也就是告訴你這個(gè)文件的編碼是什么...不幸的是Java的xml
parser, properties文件parser都不認(rèn)識(shí)這個(gè)BOM頭<http://www.uuzone.com/blog/tom/98677.htm>
!已經(jīng)有人把這個(gè)作為Bug提交給了SUN并被接受<http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058>,
可是這個(gè)bug一直拖了4年,才在去年在Mustang項(xiàng)目(Java
6.0)中解決<http://glaforge.free.fr/weblog/index.php?itemid=151&catid=2>!
我們顯然不能用了.
** 幸運(yùn)的是... *我們可以規(guī)避這些問(wèn)題, 我們并不需要把XML, properties文件轉(zhuǎn)換成UTF-8的, 只要把jsp轉(zhuǎn)了即可.
雖然一個(gè)項(xiàng)目中的文件兩種保存格式,非常不優(yōu)雅, 但畢竟這能解決問(wèn)題啊... 轉(zhuǎn)換完jsp文件,運(yùn)行項(xiàng)目, 成功! 打開(kāi)browser...頁(yè)面也出來(lái)了!
** 幾乎成功了!* 是的, 幾乎成功了...然而在計(jì)算機(jī)的世界里幾乎成功就是不成功. 因?yàn)轫?yè)面上的樣式神秘地出了輕微的混亂.
經(jīng)過(guò)n十分鐘仔細(xì)研究討論, 終于發(fā)現(xiàn)產(chǎn)生的html頁(yè)面內(nèi)出現(xiàn)了幾個(gè)神秘的不可見(jiàn)字符... 就是這些可怕的不可見(jiàn)字符, 破壞了頁(yè)面的結(jié)構(gòu).
** 神秘的隱身字符* 和計(jì)算機(jī)打交道和比人打交道強(qiáng)的一個(gè)地方就是在于 -- 如果計(jì)算機(jī)錯(cuò)了,一定是你錯(cuò)了, 因?yàn)橛?jì)算機(jī)一定忠實(shí)執(zhí)行你的指令.
神秘的不可見(jiàn)字符一定有其來(lái)歷. 經(jīng)過(guò)二進(jìn)制分析, 找到了這些神秘字符出現(xiàn)的地方 ---jsp include! 每次include就會(huì)出現(xiàn)神秘字符,
而這些神秘字符的值也是老朋友了 -- 就是BOM header !
** 難道不能include了?* 原來(lái)java顯然和xml文件一樣對(duì)待了這些BOM頭, 這些FF FE之類(lèi)的東西成了輸出的一部分. google
去查, 看到一個(gè)人顯然遇到完全相同的問(wèn)題, 可惜是個(gè)俄羅斯的程序員, 也看不懂其文章... :(
怎么辦? 有同學(xué)說(shuō): 既然你要UTF-8 (心想: 誰(shuí)讓你是boss呢? 愚蠢的boss啊...:-) ) ,
我們還是用native2ascii吧... 不行!
** 遇到困難要思考.* 思考...
首先, 為什么java文件不需要轉(zhuǎn)碼(java 文件中的中文無(wú)論如何都能正確)? 為什么jsp要? jsp不是被預(yù)編譯成java的嗎?
從那個(gè)sun承認(rèn)的bug, 顯然可以得出一個(gè)結(jié)論, java虛擬機(jī)中的file input stream沒(méi)有能自動(dòng)很具BOM識(shí)別文件編碼.
也許javac是比較native的代碼, 能通過(guò)操作系統(tǒng)獲得native編碼類(lèi)型, 而java內(nèi)部是unicode的, 所以輸出也同樣沒(méi)問(wèn)題.
而jsp是動(dòng)態(tài)編譯的, 預(yù)編譯器是JVM...其待遇顯然和xml等是一樣的...
難道sun公司的人會(huì)愚蠢到這種地步? 不可能, 一定是我們愚蠢.繼續(xù)google 學(xué)習(xí)...
不幸的是大部分google上關(guān)于這類(lèi)編碼問(wèn)題的討論都是不完整的. 但一個(gè)神秘的pageEncoding跳進(jìn)了眼簾,
已經(jīng)指定了contentType的encoding, 為什么還要指定pageEncoding? 查一下jsp的資料, 顯然這正是問(wèn)題所在!
pageEncoding就是告訴JVM 這個(gè)jsp本身采用的encoding, 默認(rèn)采用iso-8859. 我們明明用GBK的native編碼,
讓JVM拿iso8859讀取,當(dāng)然不對(duì)了!!
** 根本沒(méi)有需要轉(zhuǎn)碼, 問(wèn)題解決了!* 是的, 明白了原因所在, 把所有jsp文件頭修改為: <%@ page language="java"
contentType="text/html; charset=UTF-8" pageEncoding="GBK" %>
不需要任何轉(zhuǎn)碼,最終輸出的就是UTF-8, 沒(méi)有任何問(wèn)題. 而且這些文件采用native格式保存, 編輯最方便!
------------------------------
繁瑣寫(xiě)了一大堆,說(shuō)明了過(guò)程. 其中的教訓(xùn)是深刻的, 這就是我的標(biāo)題中的:
學(xué)藝要精,思考要慎
其實(shí),在這個(gè)問(wèn)題上折騰這么久, 只能怪自己學(xué)藝不精. pageEncoding是任何jsp的手冊(cè)上都會(huì)說(shuō)明的, 然而都被忽視了. 這個(gè)問(wèn)題
我寫(xiě)這么多,讓高人(甚至不需要高人, 只是認(rèn)真讀書(shū)看手冊(cè)的人)見(jiàn)了, 只會(huì)見(jiàn)笑 --你們太爛了. 不過(guò)從google上看, 和我們一樣爛的人太多 太多,
還有很多人在混亂編碼的泥潭中掙扎.
拉起來(lái)就做,還沒(méi)搞明白怎么回事,甚至"硬編碼"解決,害人最深.
不幸的是,遇到了太多的項(xiàng)目, 太多的人, 他們寧可copy paste大量代碼,花很多時(shí)間去debug, 費(fèi)九牛二虎之力,把boss在心中詛咒100遍,
用不正確的方法去做事, 最終的結(jié)果可想而知.
以此為記, 希望今后我們項(xiàng)目中能不重復(fù)這樣的錯(cuò)誤, 也希望我們每個(gè)人,能多思考,用聰明而省力的方法去解決問(wèn)題,而不是蠻干.
發(fā)送彩信到 1297868.3. 9...@uublog.com 可直接評(píng)論該blog
老冒 <http://www.uuzone.com/uu/mao/> 發(fā)表于 2006-04-27 21:47
閱讀<http://www.uuzone.com/blog/mao/98921.htm#>(
3001 <http://www.uuzone.com/blog/mao/98921.htm#> ) 評(píng)論(
10)<http://www.uuzone.com/blog/mao/98921.htm#comments> 引用(
0) <http://www.uuzone.com/blog/mao/98921.htm#TrackBack>
老冒觀(guān)點(diǎn)<http://www.uuzone.com/blog/mao/278/>
所有人可見(jiàn)
引用 http://www.uuzone.com/app/trackBack.do?type=blog&trackBackID=98921
<http://www.uuzone.com/app/blogTopicPostLoad.do?type=1&trackBackID=98921>
相關(guān)內(nèi)容
更多.. <http://www.uuzone.com/blog/mao/278/>
- 玩計(jì)算的家伙們都喜歡飛機(jī)? <http://www.uuzone.com/blog/mao/98723.htm>
- 沒(méi)有基本職業(yè)素養(yǎng)的秘書(shū)為何支持率高達(dá)八成? <http://www.uuzone.com/blog/mao/98899.htm>
- 用心做事和用力做事 <http://www.uuzone.com/blog/mao/99722.htm>
10評(píng)論 1
[image: 汪洋里的海盜 優(yōu)友:378 照片:450] <http://www.uuzone.com/uu/tommyhuang/>
汪洋里的海盜 <http://www.uuzone.com/blog/tommyhuang/> 說(shuō):
不錯(cuò)
2006-04-27 23:06:36(5個(gè)月前) 評(píng)論.
2
[image: Caiwangqin 優(yōu)友:104 照片:271] <http://www.uuzone.com/uu/uu_1115110/>
Caiwangqin <http://www.uuzone.com/blog/uu_1115110/> 說(shuō):
這是JAVA的失敗(當(dāng)然更多的還是學(xué)藝不精),中國(guó)人大概是從1996年開(kāi)始使用JAVA的,現(xiàn)在是2006年,十年過(guò)去了,JAVA還讓人們?cè)谧罨A(chǔ)的編碼工作上痛苦不堪。
JAVA is not fun for web UI.
2006-04-28 09:18:40(5個(gè)月前) 評(píng)論.
3
[image: Felix 優(yōu)友:1 照片:0] <http://www.uuzone.com/uu/gzfelix/>
Felix <http://www.uuzone.com/blog/gzfelix/> 說(shuō):
其實(shí)FileReader/FileWriter是根據(jù)默認(rèn)的文件字符編碼directive
file.encoding來(lái)編碼讀取/寫(xiě)入文件流的。你用的系統(tǒng)的字符集可能默認(rèn)不是utf-8? (例如中文版的Windows or
LC_ALL&LANG設(shè)置為非UTF-8的Linux系統(tǒng))所以有可能會(huì)出現(xiàn)類(lèi)似問(wèn)題。關(guān)鍵是要系統(tǒng)的file.encoding和文件的encoding相對(duì)應(yīng),不然就會(huì)出問(wèn)題。
JSP
Compiler一般是用InputStreamReader來(lái)讀取文件的,指定了pageEncoding之后,也就指定了InputStream的charset,所以pageEncoding指定的正是文件本身的encoding。
2006-04-28 09:52:20(5個(gè)月前) 評(píng)論.
4
[image: 老冒 優(yōu)友:1051 照片:2156] <http://www.uuzone.com/uu/mao/>
老冒 <http://www.uuzone.com/blog/mao/> 說(shuō):
Thanks felix !
2006-04-28 11:33:42(5個(gè)月前) 評(píng)論.
5
[image: Meteo 優(yōu)友:0 照片:0] <http://www.uuzone.com/uu/uu_bccogll/>
Meteo <http://www.uuzone.com/blog/uu_bccogll/> 說(shuō):
Not sure if know this site
http://www.web20workgroup.com/
It has all the latest info/news on web2.0
2006-04-28 14:43:52(5個(gè)月前) 評(píng)論.
6
[image: Meteo 優(yōu)友:0 照片:0] <http://www.uuzone.com/uu/uu_bccogll/>
Meteo <http://www.uuzone.com/blog/uu_bccogll/> 說(shuō):
+U +U , you guys are doing a good job
2006-04-28 14:47:49(5個(gè)月前) 評(píng)論.
7
[image: Meteo 優(yōu)友:0 照片:0] <http://www.uuzone.com/uu/uu_bccogll/>
Meteo <http://www.uuzone.com/blog/uu_bccogll/> 說(shuō):
btw, I didnt contact you recently because I thought you must be very very
busy. So please let me know when you are free.
2006-04-28 14:49:35(5個(gè)月前) 評(píng)論.
8
[image: 老冒 優(yōu)友:1051 照片:2156] <http://www.uuzone.com/uu/mao/>
老冒 <http://www.uuzone.com/blog/mao/> 說(shuō):
Sure I know that...
I am very busy these days...let‘s contact via email...
2006-04-28 15:02:13(5個(gè)月前) 評(píng)論.
9
[image: fireshort 優(yōu)友:0 照片:0] <http://www.uuzone.com/uu/uu_bcpxtpz/>
fireshort <http://www.uuzone.com/blog/uu_bcpxtpz/> 說(shuō):
"原來(lái)這些UTF-8的文件有一個(gè)所謂BOM <http://www.unicode.org.unicode/faq/utf_bom.html>頭"
不 是UTF-8文件就有BOM頭的,用editplus保存的UTF-8文件都沒(méi)有BOM頭。如果是在eclipse里面編輯jsp的話(huà),根本不需要管
pageEncoding。我們?cè)趈sp里也用了include,沒(méi)有設(shè)pageEncoding,在windows和linux下都好好的。
2006-10-19 10:18:43(1秒前) 評(píng)論.
編輯<http://www.uuzone.com/app/blogTopicReply.do?userID=mao&rid=134704>
聯(lián)系客服