故事起源于這周踩的一個(gè)小坑,tomcat本地調(diào)啟動(dòng)web時(shí)報(bào)錯(cuò)。錯(cuò)誤提示說(shuō)有個(gè)xml文件的編碼有問(wèn)題,我點(diǎn)進(jìn)去看了看沒(méi)看出啥異常,開(kāi)頭跟其他xml一樣指定了utf-8的格式,除了是小寫(xiě)的,我傻乎乎地去改成了大寫(xiě)。。。然后。。。肯定是沒(méi)解決啊!!!咳咳,果斷請(qǐng)教同事去了,瞅一眼,扔過(guò)來(lái)一串參數(shù)-Dfile.encoding=UTF-8,讓我在webserver的VM OPTION里面加上,成了。
恩,又是那個(gè)古老的梗,(咦,好了!但是這是為什么呢。。。)雖然從頭到尾我都不懂,但是還是篩選掉一些例如-D是什么鬼之類(lèi)的問(wèn)題吧。O(∩_∩)O。。。問(wèn)題的挖掘經(jīng)歷了幾個(gè)階段:
1.file.encoding的系統(tǒng)默認(rèn)值是什么(其實(shí)我也不知道有沒(méi)有系統(tǒng)默認(rèn)值這么個(gè)東西。。總之就是默認(rèn)值了啊。。。哈哈。。。)
首先自然想知道默認(rèn)的encoding值是什么了。我新建了一個(gè)空的工程,隨便寫(xiě)了個(gè)類(lèi),在main里面打印System.get 2.file.encoding在哪些環(huán)節(jié)會(huì)用到 找到一篇很好地文章http://cmsblogs.com/?p=1475。文章很系統(tǒng)地分析了java輸出格式的流程。在不同情況下的流程也是不同的。文章舉例了三種情況:1)直接輸出到console 2)部署到webserver輸出到web頁(yè)面 3)輸出到數(shù)據(jù)庫(kù)。這篇文章解決了我的第一個(gè)問(wèn)題,也就是為什么輸出到web沒(méi)有用到那個(gè)UTF-8。因?yàn)镾ystem.getproperty()中得到的file.encoding代表的是輸出到console時(shí)編碼格式,自然跟web頁(yè)面沒(méi)關(guān)系。 此外我還知道了,java虛擬機(jī)在處理數(shù)據(jù)時(shí),數(shù)據(jù)在內(nèi)存中存儲(chǔ)的格式均為Unicode,包括.class文件以及外部輸入的數(shù)據(jù)。這樣我可以理解成,數(shù)據(jù)在內(nèi)存中一律是以Unicode格式流轉(zhuǎn)的,需要輸出到哪個(gè)地方就再獲取對(duì)應(yīng)的file.encoding,將Unicode格式的數(shù)據(jù)再轉(zhuǎn)換成file.encoding的格式輸出。仔細(xì)一想,其實(shí)這種方式也非常符合java的平臺(tái)無(wú)關(guān)特性,畢竟有Unicode這種大殺器(能涵蓋所有字符的編碼格式我也是醉了),那自然要用它來(lái)作為統(tǒng)一的數(shù)據(jù)處理格式,至于那些關(guān)乎平臺(tái)關(guān)乎場(chǎng)景的case,再各自分情況處理。 3.所謂的默認(rèn)file.encoding值是從哪得到的 說(shuō)實(shí)話這是讓我非常頭疼的問(wèn)題,因?yàn)槌兼獙?shí)在是對(duì)工具神馬的一竅不通啊!!鬼知道TMD寫(xiě)在哪個(gè)配置文件的哪個(gè)角落里啊!!尼瑪,我繼續(xù)搜,不停地搜。好不容易找到了。。由IDE控制的針對(duì)console的file.encoding默認(rèn)設(shè)置。我用的是intellij,在$ItellijHOME/Contents/Info.plist,(這個(gè)HOME是我瞎BB的,看得懂就好了啊。。),確實(shí)找到了這么一串 <key>VMOptions</key> <string>-Dfile.encoding=UTF-8 -XX:+UseConcMarkSweepGC -XX:SoftRefLRUPolicyMSPerMB=50 -ea -Dsun.io.useCanonCaches=false -Djava.net.preferipv4Stack=true -Xverify:none -Xbootclasspath/a:../lib/boot.jar</string> <key>WorkingDirectory</key> 看到那個(gè)“-Dfile.encoding=UTF-8”木有!!成就感滿滿有木有!!!故事告一段落,最開(kāi)始找到的那個(gè)UTF-8來(lái)自于IDE的默認(rèn)設(shè)置,并且管的是console,web容器的file.encoding在tomcat運(yùn)行設(shè)置的VM OPTION重新指定為UTF-8,于是輸出的web頁(yè)面格式OK了。 但是!怎么可以就此止步!不是有g(shù)etProperty嘛,那也有setProperty啊,你不是說(shuō)輸出到哪就獲取對(duì)應(yīng)的file.encoding然后轉(zhuǎn)換unicode到file.encoding再輸出么,那我先按utf-8輸出,再setProperty成別的編碼格式,再輸出相同內(nèi)容是不是就亂碼了? 事實(shí)證明,企圖用setproperty來(lái)修改runtime的file.encoding根本不起作用,該輸出啥還是輸出啥。于是我查了一下資料,file.encoding的值在JVM初始化的時(shí)候指定的才是有效地,運(yùn)行時(shí)file.encoding壓根就是一個(gè)只讀屬性,據(jù)說(shuō)是初始化的時(shí)候存了一個(gè)cache,以后即使改了也只會(huì)讀取cache也就是初始化的值,有興趣的可以去讀一下源碼,相關(guān)的討論鏈接在這了http://stackoverflow.com/questions/1749064/how-to-find-the-default-charset-encoding-in-java。自己也照著試了一下,的確如此,我只有修改vm option才會(huì)輸出亂碼。關(guān)鍵的幾句代碼: 以上。new OutputStreamWriter(new ByteArrayOutputStream()).getEncoding();//查看有效的file.encoding,也就是初始化時(shí)候的那個(gè)cache值System.getProperty("file.encoding");//查看file.encoding的真實(shí)值,雖然真實(shí),但是無(wú)效啊。。
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注