轉(zhuǎn):Java中String與byte[]的轉(zhuǎn)換
原文地址:http://blog.csdn.net/llwan/article/details/7567906
String s = "fs123fdsa";//String變量
byte b[] = s.getBytes();//String轉(zhuǎn)換為byte[]
String t = new String(b);//bytep[]轉(zhuǎn)換為String
做JAVA經(jīng)常會(huì)碰到中文亂碼問(wèn)題,還有各種編碼的問(wèn)題,,特別是String類的內(nèi)容需要重新編碼的問(wèn)題,。要解決這些問(wèn)題,必須了解清楚JAVA對(duì)于字符串是怎么處理的,。
1. “字符”是由數(shù)字來(lái)表示的
先來(lái)重新了解一下計(jì)算機(jī)是如何處理“字符”的,,這個(gè)原理是大家必須記住的,特別是在用JAVA寫(xiě)程序的時(shí)候,,萬(wàn)萬(wàn)不可模糊,。我們知道,,計(jì)算機(jī)把任何東西都用數(shù)字來(lái)表示,“字符”也不例外,。比如我們要顯示一個(gè)阿拉伯?dāng)?shù)字“3”,,在我們的PC里,其實(shí)并不是僅僅用一個(gè)數(shù)字3來(lái)代表我們要寫(xiě)的“3”,,而是以十六進(jìn)制的0x33來(lái)代表,,包括放在內(nèi)存或者是寫(xiě)到文件里,其實(shí)都是寫(xiě)著0x33的,,不信你可以編輯一個(gè)文本文件,,寫(xiě)一個(gè)“3”,然后用ultraEdit看他的原始碼,。
2. 一切“字符”都必定用數(shù)字+編碼表表示,。
這時(shí)候,有一個(gè)問(wèn)題:為什么一定要用0x33來(lái)代表“3”呢,?而不用0x43來(lái)代表呢,?或者是直接用0x03來(lái)代替?其實(shí)用什么來(lái)代表都可以,,只不過(guò)大家都習(xí)慣了用ASCII編碼表(是美國(guó)國(guó)家信息交換表)來(lái)確定各字符應(yīng)該是用什么數(shù)字代表的,。同樣,為了表示中國(guó)字,,我國(guó)也指定了中文的編碼表,,其中最廣泛使用的是GB2312。比如中文的“當(dāng)”字,,就是用0xB5, 0xB1這兩個(gè)八位的數(shù)字來(lái)表示的,。所以如果顯示字符的程序不知道一列數(shù)字到底是按什么編碼表編碼的,他也無(wú)法去判斷到底這些是什么文字,。如果隨便用一個(gè)不對(duì)的編碼表來(lái)處理這些數(shù)字,,處理出來(lái)的字符很可能完全是錯(cuò)的。比如在英文系統(tǒng)上,,沒(méi)有GB2312編碼表,,送給他一個(gè)0xB5,0xB1,他就傻傻的當(dāng)作ASCII來(lái)處理(操作系統(tǒng)通常都有自己默認(rèn)的編碼表),,結(jié)果顯示出來(lái)就是兩個(gè)奇怪的符號(hào),,因?yàn)檫@兩個(gè)字在ASCII表里就是那兩個(gè)符號(hào)。同樣在繁體中文系統(tǒng)里,,他的編碼表是BIG5,,顯示出來(lái)也是一個(gè)奇怪的中文,不是“當(dāng)”字,。
3. UNICODE讓全世界都說(shuō)一種語(yǔ)言
看完上面的文字,,是否覺(jué)得,,世界有那么多語(yǔ)言,每個(gè)都有自己的一套編碼表,,很麻煩呢,?就算是中文,也有兩套流行的編碼表,,一個(gè)是GB2312,,一個(gè)是BIG5。要使用不同中文的編碼的字符時(shí),,還要轉(zhuǎn)來(lái)轉(zhuǎn)去,,的確很麻煩。不光這個(gè),,如果想要寫(xiě)一篇包含很多過(guò)國(guó)文字的文章,,就麻煩了,必須要讓處理這個(gè)文章的程序知道,,哪個(gè)字是什么編碼標(biāo)準(zhǔn)的,。如果你想要在文章里找一個(gè)字,也必須指定你要找的是哪種編碼的哪個(gè)字,。否則,,你要找一個(gè)0xB5,0xB1的中文“當(dāng)”字,,很可能把同樣數(shù)字表示的日文,、波蘭文這些不相干的字一起給你找出來(lái),夠麻煩的吧,!
所以人們想,,不如大家都用同一個(gè)編碼標(biāo)準(zhǔn)吧,各種文字都在編碼表里有一席之地,,處理文字的程序只需要都按這個(gè)編碼表來(lái)處理就可以了,。不過(guò)要一個(gè)編碼表里包含所有的文字,這張表就大了,,本來(lái)英文字+數(shù)字一共只有128個(gè)以內(nèi),。但加上中文后,忽然就多了數(shù)萬(wàn)個(gè),,所以存放一個(gè)字符需要的大小也大了很多?,F(xiàn)在UNICODE規(guī)定了一個(gè)字符必須由2個(gè)8位數(shù)字來(lái)表示,想想,,8x8x8x8x = 65536 ,,是多大的一個(gè)數(shù)字啊,!所以全世界的文字才能都包含進(jìn)去,。當(dāng)然拉,,也有人說(shuō)中國(guó)字可能都不止6萬(wàn)個(gè)拉,還要包括別的文字,,但人家外國(guó)人覺(jué)得你們中國(guó)人常用的也沒(méi)那么多,,所以就這么定了,我們也沒(méi)辦法,。需要注意的是GB2312和UNICODE雖然都是用兩個(gè)8位數(shù)來(lái)代表一個(gè)中文字,,但具體的規(guī)格可不一樣,比如0xB5,0xB1在UNICODE里面可不是“當(dāng)”字,,而是另外一國(guó)的文字來(lái)的,。
4. C是如何簡(jiǎn)潔的處理字符的
我們來(lái)談?wù)凜的字符串。C語(yǔ)言誕生在JAVA之前,,C語(yǔ)言的基本數(shù)據(jù)類型是沒(méi)有字符串這個(gè)類型的,,它只有char[]。也就是C把字符順序放入一個(gè)字節(jié)數(shù)組就完了,。而且C也不管放在數(shù)組里的是什么文字,,也不管那些字是按什么編碼標(biāo)準(zhǔn)的。而且他的char的大小也不一定是8位數(shù)字,,有時(shí)候是16位也可能,,這要看具體的機(jī)器和操作系統(tǒng)。所以寫(xiě)程序的人必須要知道正在處理的char[]的內(nèi)容到底是按什么編碼表表示的字符串,,要知道如果比較兩國(guó)文字是否相同,,可是沒(méi)任何意義的哦!
5. JAVA是是如何處理字符的,。
世界總會(huì)進(jìn)步的,,JAVA就是一個(gè)例子。JAVA終于有了String類了,,它是解決字符問(wèn)題的最好工具,。在JAVA里,一個(gè)基本的要點(diǎn)是:String類對(duì)象是不需要指定編碼表的,!為什么它會(huì)自己知道一堆數(shù)字各代表什么字符呢,?就是因?yàn)镾tring里的字符信息是用UNICODE編碼存放的。而JAVA為了表示字符(注意是單個(gè)字符),,也有char這個(gè)數(shù)據(jù)類型,,而且他的大小是固定2個(gè)8位16進(jìn)制數(shù)字長(zhǎng)度,也就是0~65535羅,。為的就是對(duì)應(yīng)UNICODE里面的一個(gè)字符,。大家如果想取一個(gè)String里的按UNICODE數(shù)字,可以用getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) 方法取得一個(gè)char[],這個(gè)char[]里就是表示String字符的,,按UNICODE編碼表編碼的數(shù)字,。
可惜現(xiàn)在絕大多數(shù)的系統(tǒng)和程序都不是按UNICODE來(lái)處理字符,而JAVA程序總是要和別的程序和系統(tǒng)交換數(shù)據(jù)的,,所以在接收一個(gè)字符,,或者是發(fā)送一個(gè)字符的時(shí)候,就必須要留意當(dāng)前系統(tǒng)和UNICODE的關(guān)系了,。比如你從網(wǎng)絡(luò)或者文件接受到一數(shù)字:0xB5,0xB1,,JAVA程序并不知道這兩個(gè)字到底是中文呢?還是日文,,或者英文,。你如果不指明這個(gè)兩個(gè)數(shù)字的編碼表,JAVA就會(huì)按當(dāng)前系統(tǒng)默認(rèn)的編碼表來(lái)處理,。如果這兩個(gè)數(shù)字是從中文WIN98發(fā)出去的,,JAVA程序又是在英文LINUX上運(yùn)行的,那就出現(xiàn)了所謂的亂碼問(wèn)題了,。也就是JAVA按英文的編碼表ASCII來(lái)處理這兩個(gè)數(shù)字,,當(dāng)通過(guò)new String({0xB5,0xB1})得到的String的時(shí)候,這個(gè)String代表的已經(jīng)不是中文的“當(dāng)”字,,而是兩個(gè)英文的奇怪字符了,。不過(guò)如果你知道這兩個(gè)數(shù)字一定是中文的話,就可以指定用new String({0xB5,0xB1},"GB2312")來(lái)處理,,這時(shí)候新建立的String才真的是一個(gè)“當(dāng)”字,。當(dāng)然拉,如果你要把一個(gè)“當(dāng)”字的JAVA的String顯示在中文WIN98上,,必須把這個(gè)字輸出成兩個(gè)8位數(shù)字:0xB5,0xB1,,不管是寫(xiě)成文件還是輸出到瀏覽器上,都必須是0xB5,0xB1,。如何把“當(dāng)”字用GB2312輸出?String.getBytes("GB2312")就可以拉,!所以有一點(diǎn)要記?。汉屯饨缃粨Q任何信息都是以byte[]來(lái)進(jìn)行的!,。你可以留意一下JAVA大多數(shù)的I/O類,,都有以byte[]作為參數(shù)和返回值的方法。不過(guò),,也有很多寫(xiě)的比較糊涂的程序,,沒(méi)有提供byte[]交換信息的方法,害的不同文字平臺(tái)的程序員很頭疼。Servlet的HttpRequest.getParameter()就是這樣,。好在有的JSP/SERVLET容易還提供先指定編碼表的方法,,才能比較簡(jiǎn)單的解決這個(gè)問(wèn)題。
6. 網(wǎng)上關(guān)于JAVA中文問(wèn)題的一些錯(cuò)誤處理方法,。
一個(gè)是最常見(jiàn)的,,不管什么內(nèi)容,都用new String(...,"ISO-8859-1")來(lái)建立字符串,,然后使用的時(shí)候按默認(rèn)的編碼格式(通常在服務(wù)器上都是英文系統(tǒng))輸出字符串,。這樣其實(shí)你使用的String并不是按UNICODE來(lái)代表真正的字符,而是強(qiáng)行把BYTE數(shù)組復(fù)制到String的char[]里,,一旦你的運(yùn)行環(huán)境改變,,你就被迫要修改一大堆的代碼。而且也無(wú)法在同一個(gè)字符串里處理幾種不同編碼的文字,。
另一個(gè)是把一種編碼格式的字符串,,比如是GB2312,轉(zhuǎn)換成另一種格式的字符串,,比如UTF-8,,然后不指明是UTF-8編碼,而直接用new String(...)來(lái)建立String,,這樣放在String里面的字符也是無(wú)法確定的,,它在不同的系統(tǒng)上代表不同的字符。如果要求別人用“UTF-8格式”的String來(lái)交換信息的時(shí)候,,其實(shí)已經(jīng)破壞了JAVA為了兼容各種語(yǔ)言所做的規(guī)定,。這種錯(cuò)誤的本質(zhì)思想是還按寫(xiě)C語(yǔ)言的方式,把字符串純粹當(dāng)作可以自己自由編碼的存儲(chǔ)器使用,,而忽略了JAVA字符串只有一種編碼格式,。如果真的想自由編碼,用byte[]或者char[]就完全了解決問(wèn)題的了,。
以上,,除了是解決JAVA中文問(wèn)題的基礎(chǔ)知識(shí)外,也是多年前應(yīng)該掌握的計(jì)算機(jī)基礎(chǔ)知識(shí),。溫故而知新,,以期共勉。