我們先來看一看開發過程中的可能遇到了乙個小問題:
你是不是像我一樣理所當然的認為:通過byte陣列構建的字串還可以通過getbytes()方法變回原來的byte陣列(實在是太天真了)
。
我們知道byte的範圍是 -128~127
當陣列中的所有byte數值大於0時,它通過構建成string後確實可以得到原來的byte陣列:
byte
bytes =
newbyte
; system.out.
println
(arrays.
tostring
(bytes));
//[45, 18, 19, 36, 57, 79, 100, 43]
string str =
newstring
(bytes)
;byte
newbytes = str.
getbytes()
; system.out.
println
(arrays.
tostring
(newbytes));
//[45, 18, 19, 36, 57, 79, 100, 43]
是不是沒有一點錯?
是不是所有時候都可以這樣轉化呢?
不!
當byte陣列中有乙個元素它小於0,那就翻車了:
byte
bytes =
newbyte
; system.out.
println
(arrays.
tostring
(bytes));
//[-45, 18, 19, 36, 57, 79, 100, 43]
string str =
newstring
(bytes)
;byte
newbytes = str.
getbytes()
; system.out.
println
(arrays.
tostring
(newbytes));
//[-17, -65, -67, 18, 19, 36, 57, 79, 100, 43]
你不能保證每個位元組都是大於0的吧,所以這樣的不行的。
那問題出在哪呢??
為什麼就構建不回去??
因為:我們構建字串時,預設使用的是我們整合開發環境的編碼(idea預設採用的是utf-8全域性編碼,單個專案採用與系統保持一致的(windows是gbk,linux是utf-8)編碼,我用的window系統),而utf-8是多位元組編碼的,它會用乙個或多個位元組來表示乙個乙個的字元,所以,請看如下**:
byte
bytes =
newbyte
; system.out.
println
(arrays.
tostring
(bytes));
//[-45, 18, 19, 36, 57, 79, 100, 43]
string str =
newstring
(bytes)
; system.out.
println
(str.
length()
);//8byte
newbytes = str.
getbytes()
; system.out.
println
(newbytes.length)
;//10
system.out.
println
(arrays.
tostring
(newbytes));
//[-17, -65, -67, 18, 19, 36, 57, 79, 100, 43]
我只列印了str的長度了newbytes的長度,你會發現str的長度是正常的,而newbytes的長度多了2個。
如前所述,utf-8編碼有時會把乙個字元拆分成多個位元組表示,那什麼時候會進行拆分呢,就是當位元組的數值小於1的時候。
就像**中的,它把byte值-45拆分成了3個位元組。
這就導致了前後不一致的問題。
解決辦法:
網上有人說,使用單位元組編碼(iso-8859-1),親測確實有效,但是必須注意使用byte陣列構建string的時候指定編碼集,string通過getbytes轉化回去的時候也必須指定編碼集!。
byte
bytes =
newbyte
; system.out.
println
(arrays.
tostring
(bytes));
//[-45, 18, 19, 36, 57, 79, 100, 43]
string str = null;
byte
newbytes = null;
trycatch
(unsupportedencodingexception e)
system.out.
println
(arrays.
tostring
(newbytes));
//[-45, 18, 19, 36, 57, 79, 100, 43]
可以看到構建出的byte陣列前後完全一致,省去了利用迴圈賦值的操作(因為我的需求是從byte陣列中拿到有效元素後再構建成乙個byte陣列)。
如果不使用中間變數string(byte–>string–>byte)的話,我的**就可能必須得套一層迴圈了:
byte
bytes =
newbyte
; system.out.
println
(arrays.
tostring
(bytes));
//[-45, 18, 19, 36, 57, 79, 100, 43, 0, 0, 0]
int count =5;
//假設有效元素個數為5個,前5個(-45,18,19,36,57)
byte
newbytes =
newbyte
[count]
;for
(int i =
0;i) system.out.
println
(arrays.
tostring
(newbytes));
//[-45, 18, 19, 36, 57]
如果你不了解字符集編碼的話,到最後就只能乖乖迴圈。
《鋒利的 jquery》一書的作者曾強調:每多學一點知識,就少些一行**。
接下來我們進入正文?
字符集,顧名思義,就是許多許多個字元的集合。
而字符集編碼,就是這些字符集拆分和組合的規則。
字元(character)是文字和符號的總稱。
現實世界中我們可以看到,即使不同國家有著各式各樣的不同的文字(中文,韓文,日文),但是它們都在使用著英文本母和阿拉伯數字。
計算機最早產生是按照英語單詞中的單個字母以及阿拉伯數字和一些符號設計的。
我們知道,字母、數字、符號它們都是單位元組的,只占用乙個位元組(8bit),它最多可以儲存256種字元(足以儲存現有的全部字元,0~9數字和常用符號),但所有國家的文字遠遠超過256了。乙個位元組根本不可能存的下,只能進行拆分,例如把乙個漢字拆分成2個位元組,然後再拼接回去。前後一拆一組,便是不同的字元編碼決定的。
因此,拆分和組合的規則,就是所謂的字元編碼。
編碼規範:
所謂字符集其實是一套編碼規範中的子概念,為了顯示字元,國際組織就制定了編碼規範,希望使用不同的二進位制數來表示代表不同的字元,這樣電腦就可以根據二進位制數來顯示其對應的字元。我們通常就稱呼其為xx編碼,xx字符集。
常見的字元編碼:
另外,作業系統平台預設字符集:
windows:gbk
linux:utf-8
整合開發環境使用的預設編碼:
intellij idea:utf-8
eclipse:gbk
大多數文字處理軟體都可以指定字符集編碼。
比如建立乙個記事本檔案,預設使用的是ansi,它的意思就是使用作業系統預設編碼方式。
不同的國家和地區制定了不同的標準,由此產生了 gb2312、gbk、gb18030、big5、shift_jis 等各自的編碼標準。這些使用多個位元組來代表乙個字元的各種漢字延伸編碼方式,稱為 ansi 編碼。在簡體中文windows作業系統中,ansi 編碼代表 gbk 編碼;在正體中文windows作業系統中,ansi編碼代表big5;在日文windows作業系統中,ansi 編碼代表 shift_jis 編碼。本文參考自:
你不知道的 字符集和編碼(編碼字符集與字符集編碼)
我的上篇文章,有朋友提出字符集和編碼的區別,我在此立文和大家討論下 常說的字符集和編碼區別,其實就是編碼字符集和字符集編碼的區別,其實,單單如果只是說字符集,沒有任何編碼的概念的話,那麼字符集其實僅僅是乙個簡單的字元的集合,或者說是乙個抽象的字元的集合,包括文字,符號等等,不參與任何儲存形式,只是存...
Unicode了解一下 編碼演算法
utf 8是一種字元長度可變的unicode編碼方式。他可以編碼unicode中的所有碼位,共 17 216 2048 b mp.s urro gate 1112064 個 17 2 16 2048 b mp.s urro gate 1112064 個utf 8的規則很簡單 我們來看一下unicod...
深入了解字符集和編碼問題
對於字符集,編碼的問題,一直都搞不太明白,下面好好學習一下 一 什麼是字符集?什麼是編碼?一組抽象 可能按某一維度來區分不同的字元,比如按照語言,將字元分類,分為中文字符集 英文字符集 字元的集合就是字符集 charset 它是字元的集合,也可以理解為字元的分類,比如英文字符集 中文字符集等。每種編...