日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

NIO--字符集

發布時間:2024/4/13 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 NIO--字符集 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

字符集基礎

術語

  • Character Set(字符集)

字符的集合,也就是帶有特殊語義的符號。字母“A”是一個字符。“%”也是一個字符。沒有內在數字價值,與ASCII,Unicode,甚至是電腦也沒有任何的直接聯系。在電腦產生前的很長一段時間內,符號就已經存在了。

  • Coded Character Set(編碼字符集)

一個數值賦給一個字符的集合。把代碼賦值給字符,這樣它們就可以用特定的字符編碼集表達數字的結果。其他的編碼字符集可以賦不同的數值到同一個字符上。字符集映射通常是由標準組織確定的,例如USASCII,ISO 8859-1,Unicode (ISO 10646-1),以及JIS X0201。

  • Character-encoding scheme(字符編碼方案)

編碼字符集成員到八位字節(8bit字節)的映射。編碼方案定義了如何把字符編碼的序列表達為字節序列。字符編碼的數值不需要與編碼字節相同,也不需要是一對一或一對多個的關系。原則上,把字符集編碼和解碼近似視為對象的序列化和反序列化。

通常字符數據編碼是用于網絡傳輸或文件存儲。編碼方案不是字符集,它是映射;但是因為它們之間的緊密聯系,大部分編碼都與一個獨立的字符集相關聯。例如,UTF-8,僅用來編碼Unicode字符集。盡管如此,用一個編碼方案處理多個字符集還是可能發生的。例如,EUC可以對幾個亞洲語言的字符進行編碼。
圖6-1是使用UTF-8編碼方案將Unicode字符序列編碼為字節序列的圖形表達式。UTF-8把小于0x80的字符代碼值編碼成一個單字節值(標準ASCII)。所有其他的Unicode字符都被編碼成2到6個字節的多字節序列(http://www.ietf.org/rfc/rfc2279.txt)。

  • Charset(字符集)

術語charset是在RFC2278(http://ietf.org/rfc/rfc2278.txt)中定義的。它是編碼字符集和字符編碼方案的集合。java.nio.charset包的錨類是Charset,它封裝字符集抽象。

字符編碼成UTF-8

?

字符集

字符集名稱不區分大小寫,也就是,當比較字符集名稱時認為大寫字母和小寫字母相同。

UTF-8

8-位UCS轉換格式。由RFC2279以及Unicode標準3.0(修正版)指定。這是字位導向的字符編碼。小于0x80的ASCII字符被編碼為單字節。其他字符被編碼為兩個或多個字節。對于多個序列,用首字節的高序位編碼下面字節的數量。(見http://www.ietf.org/rfc/rfc2279.txt。)UTF-8與ASCII的互操作良好,因為簡單的ASCII文件就是良好的UTF-8編碼,而小于0x80的字符的UTF-8編碼就是ASCII文件。

UTF-8是一種變長字節編碼方式。對于某一個字符的UTF-8編碼,如果只有一個字節則其最高二進制位為0;如果是多字節,其第一個字節從最高位開始,連續的二進制位值為1的個數決定了其編碼的位數,其余各字節均以10開頭。UTF-8最多可用到6個字節。?
如表:?

1字節 0xxxxxxx?
2字節 110xxxxx 10xxxxxx?
3字節 1110xxxx 10xxxxxx 10xxxxxx?
4字節 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx?
5字節 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx?
6字節 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx?

因此UTF-8中可以用來表示字符編碼的實際位數最多有31位,即上表中x所表示的位。除去那些控制位(每字節開頭的10等),這些x表示的位與UNICODE編碼是一一對應的,位高低順序也相同。?

實際將UNICODE轉換為UTF-8編碼時應先去除高位0,然后根據所剩編碼的位數決定所需最小的UTF-8編碼位數。?
因此那些基本ASCII字符集中的字符(UNICODE兼容ASCII)只需要一個字節的UTF-8編碼(7個二進制位)便可以表示。

UTF-16

字節序

根據字節序的不同,UTF-16可以被實現為UTF-16LE或UTF-16BE,UTF- 32可以被實現為UTF-32LE或UTF-32BE。例如:

Unicode編碼UTF-16LEUTF-16BEUTF32-LEUTF32-BE
0x006C4949 6C6C 4949 6C 00 0000 00 6C 49?
0x020C3043 D8 30 DCD8 43 DC 3030 0C 02 0000 02 0C 30

那么,怎么判斷字節流的字節序呢?Unicode標準建議用BOM(Byte Order Mark)來區分字節序,即在傳輸字節流前,先傳輸被作為BOM的字符"零寬無中斷空格"。這個字符的編碼是FEFF,而反過來的FFFE(UTF- 16)和FFFE0000(UTF-32)在Unicode中都是未定義的碼位,不應該出現在實際傳輸中。下表是各種UTF編碼的BOM:

UTF編碼Byte Order Mark
UTF-8EF BB BF
UTF-16LEFF FE
UTF-16BEFE FF
UTF-32LEFF FE 00 00?
UTF-32BE00 00 FE FF
  • UTF-16BE,其后綴是 BE 即 big-endian,大端的意思。大端就是將高位的字節放在低地址表示。
  • UTF-16LE,其后綴是 LE 即 little-endian,小端的意思。小端就是將高位的字節放在高地址表示。
  • UTF-16,沒有指定后綴,即不知道其是大小端,所以其開始的兩個字節表示該字節數組是大端還是小端。即FE FF表示大端,FF FE表示小端。
    ?

字符集類

Charset類封裝特定字符集的信息。Charset是抽象。通過調用靜態工廠方法forName()獲得具體實例,導入所需字符集的名稱。所有的Charset方法都是線程安全的;單一實例可以在多個線程中共享。

可以調用布爾類(boolean class)方法isSupported()來確定在JVM運行中當前指定的字符集是否可用。通過Charset SPI機制可以動態安裝新的字符集,所以給定字符集名稱的答案可以隨時間變化。

一個字符集可以有多個名稱。通常它有一個規范名稱但是也有零個或多個別名。規范名稱或別名都可以通過forName()和isSupported()進行使用。

一些字符集也有歷史遺留的名稱,它們用于之前的Java平臺版本并且向后兼容。字符集的歷史名稱是由InputStreamReader和OutputStream-Writer類的getEncoding()返回。如果字符集有歷史名稱,那么它將是規范名稱或者Charset的別名之一。Charset類不提供歷史名稱的標示。靜態類方法的最后一個,availableCharsets(),將返回在JVM中當前有效的所有字符集的java.util.SortedMap。正如isSupported(),如果安裝新的字符集返回的值會隨著時間改變。返回映射的成員將是用它們的規范名稱作為密鑰的Charset對象。迭代時,映射將根據規范名稱按字母順序排列。

package java.nio.charset; public abstract class Charset implements Comparable {public static boolean isSupported (String charsetName)public static Charset forName (String charsetName)public static SortedMap availableCharsets()public final String name()public final Set aliases()public String displayName()public String displayName (Locale locale)public final boolean isRegistered()public boolean canEncode()public abstract CharsetEncoder newEncoder();public final ByteBuffer encode (CharBuffer cb)public final ByteBuffer encode (String str)public abstract CharsetDecoder newDecoder();public final CharBuffer decode (ByteBuffer bb)public abstract boolean contains (Charset cs);public final boolean equals (Object ob)public final int compareTo (Object ob)public final int hashCode()public final String toString() }

字符集比較

public abstract class Charset implements Comparable {// This is a partial API listingpublic abstract boolean contains (Charset cs);public final boolean equals (Object ob);public final int compareTo (Object ob);public final int hashCode();public final String toString(); }

字符集是由字符的編碼集與該字符集的編碼方案組成的。與普通的集合類似,一個字符集可能是另一個字符集的子集。一個字符集(C1)包含另一個(C2),表示在C2中表達的每個字符都可以在C1中進行相同的表達。每個字符集都被認為是包含其本身。如果這個包含關系成立,那么您在C2(被包含的子集)中編碼的任意流在C1中也一定可以編碼,無需任何替換。

contains()實例方法顯示作為參數傳入的Charset對象是否被該Charset對象封裝的字符集所包含。該方法不能在運行時動態比較字符集;只有當具體的Charset類確定給出的字符集被包含的情況下才返回true。如果contains()返回false,表示包含關系不存在或未知的包含關系。

如果一個字符集被另一個包含,這不意味著產生的編碼字節序列將會等同于給定的輸入字符序列。

Charset類明確地覆蓋了Object.equals()方法。如果Charset的實例擁有相同的規范名稱(由name()返回),它們就被認為是相同的。在JDK1.4.0版本中,由equals()實現的比較是規范名稱串的簡單比較,這意味著在測試過程中區分大小寫。這是在未來的版本中應該更正的錯誤程序。由于Charset.equals()方法覆蓋了Object類中的默認方法,它必須聲明為接受一個Object類的參數,而不是Charset類。Charset類的對象永遠不會與其他任意類的對象相等。

字符集編碼器

這里有用的第一個API方法是canEncode()。該方法表示這個字符集是否允許編碼。幾乎所有的字符集都支持編碼。主要的例外情況是帶有解碼器的字符集,它們可以自檢測字節序列是如何編碼并且之后會選擇一個合適的解碼方案。這些字符集通常只支持解碼并且不創建自己的編碼。

如果該Charset對象能夠編碼字符序列,canEncode()方法返回true。如果為false,上面列出的其他三個方法不應該在那個對象上被調用。這樣做將引發UnsupportedOperationException。

調用newEncoder()返回CharsetEncoder對象,可以使用和字符集相關的編碼方案把字符序列轉化為字節序列。之后我們將在本節中學習CharsetEncoder類的API,但是首先我們要快速瀏覽一下Charset余下的兩個方法。

Charset的兩個encode()方法使用方便,用默認值針對和字符集相關的編碼器實現編碼。兩個都返回新ByteBuffer對象,包含符合給定的String或CharBuffer字符的一個編碼字節序列。解碼器通常都在CharBuffer對象上運行。encode()的形式采用String參數自動的為您創建一個臨時的CharBuffer,等同于下面這個:

charset.encode (CharBuffer.wrap (string));

在Charset對象上調用encode()使用編碼器的默認設置,等同于下列代碼:

charset.newEncoder( ) .onMalformedInput (CodingErrorAction.REPLACE) .onUnmappableCharacter (CodingErrorAction.REPLACE) .encode (charBuffer);

?CharsetEncoder:

package java.nio.charset; public abstract class CharsetEncoder { public final Charset charset() public final float averageBytesPerChar() public final float maxBytesPerChar() public final CharsetEncoder reset() public final ByteBuffer encode (CharBuffer in) throws CharacterCodingException public final CoderResult encode (CharBuffer in, ByteBuffer out, boolean endOfInput) public final CoderResult flush (ByteBuffer out) public boolean canEncode (char c) public boolean canEncode (CharSequence cs) public CodingErrorAction malformedInputAction() public final CharsetEncoder onMalformedInput (CodingErrorAction newAction) public CodingErrorAction unmappableCharacterAction() public final CharsetEncoder onUnmappableCharacter ( CodingErrorAction newAction) public final byte [] replacement() public boolean isLegalReplacement (byte[] repl) public final CharsetEncoder replaceWith (byte[] newReplacement) }

CharsetEncoder對象是一個狀態轉換引擎:字符進去,字節出來。一些編碼器的調用可能需要完成轉換。編碼器存儲在調用之間轉換的狀態。

這里列出的首個方法組提供跟CharsetEncoder對象有關的永恒信息。每個編碼器和一個Charset對象相關聯,而charset()方法返回一個備份參考。

averageBytesPerChar()方法返回一個浮點值,表示編碼集合的字符所需的平均字節數量。注意該值可以是分數值。當編碼字符時,編碼運算法則可以選擇調節字節邊界,或者一些字符可以編碼成大于其他字節的字節(UTF-8就是這樣工作的)。該方法作為一個程序的探索很有用,用來確定ByteBuffer的近似尺寸,ByteBuffer需要包含給定字符的編碼字節。

最后,maxBytesPerChar()方法表示在集合中編碼單字符需要的最大字節數。這也是一個浮點值。與averageBytesPerChar()類似,該方法被用來按大小排列ByteBuffer。用maxBytesPerChar()返回的值乘以被編碼的字符數量將得出最壞情況輸出緩沖區大小。

越簡單的encode()形式越方便,在重新分配的ByteBuffer中您提供的CharBuffer的編碼集所有的編碼于一身。這是當您在Charset類上直接調用encode()時最后調用的方法。

當使用CharsetEncoder對象時,在編碼之前或編碼期間有設置錯誤處理參數的選項。(本節的后半段將討論處理編碼錯誤。)調用encode()的單參數形式實現完整的編碼循環(復位,編碼以及清理),所以編碼器之前的內狀態將丟失。
讓我們詳細了解一些編碼處理的工作原理。CharsetEncoder類是一個狀態編碼引擎。實際上,編碼器有狀態意味著它們不是線程安全的:CharsetEncoder對象不應該在線程中共享。編碼可以在一個簡單的步驟中完成,如上面提到的encode()的首個形式,或者重復調用encode()的第二個形式。編碼過程如下:
1. 通過調用reset()方法復位編碼器的狀態。讓編碼引擎準備開始產生編碼字節流。新建的CharsetEncoder對象不需要復位,但是這么做也無妨。
2. 不調用或多次調用encode()為編碼器提供字符,endOfInput參數false表示后面可能有更多的字符。給定的CharBuffer將消耗字符,而編碼字節序列將被添加到提供的ByteBuffer上。
返回時,輸入CharBuffer可能不是全部為空。可能輸出ByteBuffer會填入,或者編碼器可能需要更多的輸入來完成多字符轉化。編碼器本身可能也保留可以影響序列轉化實現的狀態。在重新填入前緊湊輸入緩沖區。
3. 最后一次調用encode(),針對endOfInput參數導入true。提供的CharBuffer可能包含額外的需要編碼的字符或為空。重要的是endOfInput在最后的調用上為true。這樣就通知編碼引擎后面沒有輸入了,允許它探測有缺陷的輸入。
4. 調用flush()方法來完成未完成的編碼并輸出所有剩下的字節。如果在輸出ByteBuffer中沒有足夠的空間,需要多次調用該方法。
當消耗了所有的輸入時,當輸出ByteBuffer為滿時,或者當探測到編碼錯誤時,encode()方法返回。無論如何,將會返回CoderResult對象,來表示發生的情況。結果對象可表示下列結果條件之一:

  • Underflow(下溢)

正常情況,表示需要更多的輸入。或者是輸入CharBuffer內容不足;或者,如果它不為空,在沒有額外的輸入的情況下,余下的字符無法進行處理。更新CharBuffer的位置解決被編碼器消耗的字符的問題。

在CharBuffer中填入更多的編碼字符(首先在緩沖區上調用compact(),如果是非空的情況)并再次調用encode()繼續。如果結束了,用空CharBuffer調用encode()并且endOfInput為true,之后調用flush()確保所有的字節都被發送給ByteBuffer。
下溢條件總是返回相同的對象實例:名為CharsetEncoder.UNDERFLOW的靜態類變量。這就使您可以使用返回的對象句柄上的等號運算符(==)來對下溢進行檢測。

  • Overflow(上溢)

表示編碼器充滿了輸出ByteBuffer并且需要產生更多的編碼輸出。輸入CharBuffer對象可能會或可能不會被耗盡。這是正常條件,不表示出錯。您應該消耗ByteBuffer但是不應該擾亂CharBuffer,CharBuffer將更新它的位置,之后再次調用encode()。重復進行直到得到下溢結果。

與下溢類似的,上溢返回一致的實例,CharsetEncoder.OVERFLOW,它可直接用于等式比較。

  • Malformed input(有缺陷的輸入)

編碼時,這個通常意味著字符包含16-位的數值,不是有效的Unicode字符。對于解碼來說,這意味著解碼器遭遇了不識別的字節序列。

返回的CoderResult實例將不是單一的參數,因為它是針對下溢和上溢的。見CoderResult的API。

  • Unmappable character(無映射字符)

表示編碼器不能映射字符或字符的序列到字節上—例如,如果您正在使用ISO-8859-1編碼但您的輸入CharBuffer包含非-拉丁Unicode字符。對于解碼,解碼器知道輸入字節序列但是不了解如何創建相符的字符。

編碼時,如果編碼器遭遇了有缺陷的或不能映射的輸入,立即返回結果對象。您也可以檢測獨立的字符,或者字符序列,來確定它們是否能被編碼。下面是檢測能否進行編碼的方法:

package java.nio.charset; public abstract class CharsetEncoder { // This is a partial API listing public boolean canEncode (char c) public boolean canEncode (CharSequence cs) }

canEncode()的兩個形式返回boolean結果,表示編碼器是否能將給出的輸入編碼。兩種方法都在一個臨時的緩沖區內實現輸入的編碼。這將引起編碼器內部狀態的改變,所以當編碼處理正在進行中時不應調用這些方法。開始編碼處理前,使用這些方法檢測您的輸入。

canEncode()的第二個形成采用類型CharSequence的一個參數,。任何實現CharSequence(當前CharBuffer, String, 或StringBuffer)的對象都可以導入到canEncode()中。

CharsetEncoder的剩下的方法包含在處理編碼錯誤中:

public abstract class CharsetEncoder { // This is a partial API listing public CodingErrorAction malformedInputAction() public final CharsetEncoder onMalformedInput (CodingErrorAction newAction) public CodingErrorAction unmappableCharacterAction() public final CharsetEncoder onUnmappableCharacter ( CodingErrorAction newAction) public final byte [] replacement() public boolean isLegalReplacement (byte[] repl) public final CharsetEncoder replaceWith (byte[] newReplacement) }

如之前提到的,CoderResult對象可以從encode()中返回,表示編碼字符序列的問題。有兩個已定義的代碼錯誤條件:malformed和unmappable。在每一個錯誤條件上都可以配置編碼器實例來采取不同的操作。當這些條件之一發生時,CodingErrorAction類封裝可能采取的操作。CodingErrorAction是無有用的方法的無價值的類。它是簡單的,安全類型的列舉,包含了它本身的靜態、已命名的實例。CodingErrorAction定義了三個公共域:

  • REPORT(報告)

創建CharsetEncoder時的默認行為。這個行為表示編碼錯誤應該通過返回CoderResult對象報告,前面提到過。

  • IGNORE(忽略)

表示應忽略編碼錯誤并且如果位置不對的話任何錯誤的輸入都應中止。

  • REPLACE(替換)

通過中止錯誤的輸入并輸出針對該CharsetEncoder定義的當前的替換字節序列處理編碼錯誤。

總結

以上是生活随笔為你收集整理的NIO--字符集的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。