異世界


2012年6月23日 星期六

Encoder vs Decoder 類別

 

編碼是將字元集轉換成位元組序列的處理程序。解碼則正好相反,它是將已編碼的位元組序列轉換成字元集的處理程序。

Encoder 可維持 GetBytes 連續呼叫之間的狀態資訊,因此它可以正確地對展開區塊的字元序列進行編碼。Encoder 也會在資料區塊尾端保留尾端字元,並在下一次編碼作業中使用該尾端字元。例如,資料區塊可能會以無對應的高 Surrogate 做為結尾,而對應的低 Surrogate 則會放在下一個資料區塊。因此,Decoder 和 Encoder 類別在網路傳輸和檔案作業中是非常有用的,因為這些作業經常會處理資料區塊,而非完整的資料流。

GetByteCount 方法判斷編碼 Unicode 字元集會產生多少位元組,而 GetBytes 方法則執行實際的編碼作業。

若要取得此類別實作的執行個體,請使用 Encoding 實作的 GetEncoder 方法。

 

Decoder 可維持 GetChars 連續呼叫之間的狀態資訊,因此它可以正確地對展開區塊的位元組序列進行解碼。Decoder 也會保留資料區塊尾端的結尾位元組,並在下一次解碼作業中使用該結尾位元組。因此,GetDecoder 和 GetEncoder 在網路傳輸和檔案作業中是非常有用的,因為這些作業經常會處理資料區塊而非完整的資料流。

GetCharCount 方法會判斷有多少字元會造成位元組序列的解碼,而由 GetChars 方法執行實際解碼。

若要取得此類別實作的執行個體,請使用 Encoding 實作的 GetDecoder 方法。

 

1.指定的編碼方式,將 Unicode 字元陣列轉換成位元組區塊。比較時,先使用 UTF7Encoding 對字元陣列進行編碼。接著,再使用 Encoder 對字元陣列進行編碼。

using System;
using System.Text;
 
class EncoderTest {
    public static void Main() {
        // The characters to encode.
        Char[] chars = new Char[] {
            '\u0023', // #
            '\u0025', // %
            '\u03a0', // Pi
            '\u03a3'  // Sigma
        };
 
        // Encode characters using an Encoding object.
        Encoding encoding = Encoding.UTF7;
        Console.WriteLine("Using Encoding\n--------------");
 
        // Encode complete array for comparison.
        Byte[] allCharactersFromEncoding = encoding.GetBytes(chars);
        Console.WriteLine("All characters encoded:");
        ShowArray(allCharactersFromEncoding);
 
        // Encode characters, one-by-one.
        // The Encoding object will NOT maintain state between calls.
        Byte[] firstchar = encoding.GetBytes(chars, 0, 1);
        Console.WriteLine("First character:");
        ShowArray(firstchar);
 
        Byte[] secondchar = encoding.GetBytes(chars, 1, 1);
        Console.WriteLine("Second character:");
        ShowArray(secondchar);
 
        Byte[] thirdchar = encoding.GetBytes(chars, 2, 1);
        Console.WriteLine("Third character:");
        ShowArray(thirdchar);
 
        Byte[] fourthchar = encoding.GetBytes(chars, 3, 1);
        Console.WriteLine("Fourth character:");
        ShowArray(fourthchar);
 
 
        // Now, encode characters using an Encoder object.
        Encoder encoder = encoding.GetEncoder();
        Console.WriteLine("Using Encoder\n-------------");
 
        // Encode complete array for comparison.
        Byte[] allCharactersFromEncoder = new Byte[encoder.GetByteCount(chars, 0, chars.Length, true)];
        encoder.GetBytes(chars, 0, chars.Length, allCharactersFromEncoder, 0, true);
        Console.WriteLine("All characters encoded:");
        ShowArray(allCharactersFromEncoder);
 
        // Do not flush state; i.e. maintain state between calls.
        bool bFlushState = false;
 
        // Encode characters one-by-one.
        // By maintaining state, the Encoder will not store extra bytes in the output.
        Byte[] firstcharNoFlush = new Byte[encoder.GetByteCount(chars, 0, 1, bFlushState)];
        encoder.GetBytes(chars, 0, 1, firstcharNoFlush, 0, bFlushState);
        Console.WriteLine("First character:");
        ShowArray(firstcharNoFlush);
 
        Byte[] secondcharNoFlush = new Byte[encoder.GetByteCount(chars, 1, 1, bFlushState)];
        encoder.GetBytes(chars, 1, 1, secondcharNoFlush, 0, bFlushState);
        Console.WriteLine("Second character:");
        ShowArray(secondcharNoFlush);
 
        Byte[] thirdcharNoFlush = new Byte[encoder.GetByteCount(chars, 2, 1, bFlushState)];
        encoder.GetBytes(chars, 2, 1, thirdcharNoFlush, 0, bFlushState);
        Console.WriteLine("Third character:");
        ShowArray(thirdcharNoFlush);
 
        // Must flush state on last call to GetBytes().
        bFlushState = true;
        
        Byte[] fourthcharNoFlush = new Byte[encoder.GetByteCount(chars, 3, 1, bFlushState)];
        encoder.GetBytes(chars, 3, 1, fourthcharNoFlush, 0, bFlushState);
        Console.WriteLine("Fourth character:");
        ShowArray(fourthcharNoFlush);
    }
 
    public static void ShowArray(Array theArray) {
        foreach (Object o in theArray) {
            Console.Write("[{0}]", o);
        }
        Console.WriteLine("\n");
    }
}

 

2.使用 Decoder 將兩個不同的位元組陣列轉換成一個字元陣列。其中一個字元的位元組會展開陣列。它和 System.IO.StreamReader 在讀取資料流時的內部作業方式類似。


using System;
using System.Text;
public class dec
{
    public static void Main()
    {
        // These bytes in UTF-8 correspond to 3 different Unicode
        // characters: space (U+0020), # (U+0023), and the biohazard
        // symbol (U+2623).  Note the biohazard symbol requires 3 bytes
        // in UTF-8 (hexadecimal e2, 98, a3).  Decoders store state across
        // multiple calls to GetChars, handling the case when one char
        // is in multiple byte arrays.
        byte[] bytes1 = { 0x20, 0x23, 0xe2 };
        byte[] bytes2 = { 0x98, 0xa3 };
        char[] chars = new char[3];
 
        Decoder d = Encoding.UTF8.GetDecoder();
        int charLen = d.GetChars(bytes1, 0, bytes1.Length, chars, 0);
        // The value of charLen should be 2 now.
        charLen += d.GetChars(bytes2, 0, bytes2.Length, chars, charLen);
        foreach(char c in chars)
            Console.Write("U+{0:X4}  ", (ushort)c);
    }
}


以上資料來源: http://msdn.microsoft.com/zh-tw/library/h5y3703w(v=vs.80)


 


3. Encoding 類別


[SerializableAttribute] 
[ComVisibleAttribute(true)] 
public abstract class Encoding : ICloneable


編碼是將 Unicode 字元集轉換成位元組序列的處理程序。解碼正好相反,它是將已編碼的位元組序列轉換成 Unicode 字元集的處理程序。

Unicode 標準會指派字碼指標 (數字) 給每個受支援指令碼中的每個字元。Unicode Transformation Format (UTF) 是用來編碼該字碼指標的方法。Unicode 標準 3.2 版使用下列 UTF:


  • UTF-8,將每個字碼指標表示成 1 到 4 個位元組的序列。

  • UTF-16,將每個字碼指標表示成 1 到 2 個 16 位元整數的序列。

  • UTF-32,將每個字碼指標表示成 32 位元整數。

.NET Framework 提供下列 Encoding 類別實作來支援目前的 Unicode 編碼方式和其他編碼方式:


  • ASCIIEncoding 可編碼 Unicode 字元成單一 7 位元 ASCII 字元。這種編碼方式只支援 U+0000 和 U+007F 之間的字元值。字碼頁 20127。也可透過 ASCII 屬性取得。

  • UTF7Encoding 會使用 UTF-7 編碼方式為 Unicode 字元編碼。這種編碼方式支援所有的 Unicode 字元值。字碼頁 65000。也可透過 UTF7 屬性取得。

  • UTF8Encoding 會使用 UTF-8 編碼方式為 Unicode 字元編碼。這種編碼方式支援所有的 Unicode 字元值。字碼頁 65001。也可透過 UTF8 屬性取得。

  • UnicodeEncoding 會使用 UTF-16 編碼方式為 Unicode 字元編碼。同時支援 Little-Endian (字碼頁 1200) 和 Big-Endian (字碼頁 1201) 位元組順序。也可透過 Unicode 屬性和 BigEndianUnicode屬性取得。

  • UTF32Encoding 會使用 UTF-32 編碼方式為 Unicode 字元編碼。同時支援 Little-Endian (字碼頁 65005) 和 Big-Endian (字碼頁 65006) 位元組順序。也可透過 UTF32 屬性取得。

使用 GetEncoding 方法取得其他編碼方式。使用 GetEncodings 方法,取得所有編碼方式的清單。

 

GetByteCount 方法判斷編碼 Unicode 字元集會產生多少位元組,而 GetBytes 方法則執行實際的編碼作業。

同樣地,GetCharCount 方法會判斷有多少字元會造成位元組序列的解碼,而由 GetChars 方法執行實際解碼。

如果要轉換的資料只可以從連續區塊 (例如從資料流讀取的資料) 取得時,或資料量太大而必須分成較小區塊時,請分別使用衍生類別的 GetDecoder 方法或 GetEncoder 方法提供的 DecoderEncoder

UTF-16 和 UTF-32 編碼器可以使用 Big-Endian 位元組順序 (最大顯著性位元組在前) 或 Little-Endian 位元組順序 (最小顯著性位元組在前)。例如,拉丁大寫字母 A (U+0041) 會序列化如下 (使用十六進位):


  • UTF-16 Big-Endian 位元組順序:00 41

  • UTF-16 Little-Endian 位元組順序:41 00

  • UTF-32 Big-Endian 位元組順序:00 00 00 41

  • UTF-32 Little-Endian 位元組順序:41 00 00 00

或是,Encoding 會提供前序編碼,這會是位元組陣列,您可將它加在編碼過程所得位元組序列的前面。如果前序編碼含有位元組順序標記 (Unicode 中的字碼指標 U+FEFF),就可以協助解碼器判斷位元組順序和轉換格式或 UTF。Unicode 位元組順序標記會序列化為如下所示 (以十六進位方式):


  • UTF-8:EF BB BF

  • UTF-16 Big-Endian 位元組順序:FE FF

  • UTF-16 Little-Endian 位元組順序:FF FE

  • UTF-32 Big-Endian 位元組順序:00 00 FE FF

  • UTF-32 Little-Endian 位元組順序:FF FE 00 00

使用原生的位元組順序來儲存 Unicode 字元,通常會更有效率。例如,在 Intel 電腦之類的 Little-Endian 平台上,最好使用 Little-Endian 位元組順序。

GetPreamble 方法會傳回可包含位元組順序標記的位元組陣列。如果此位元組陣列有前置編碼的資料流,將有助於解碼器識別所用的編碼格式。

如需位元組順序和位元組順序標記的詳細資訊,請參閱 www.unicode.org 網站上的<The Unicode Standard>。

 


EX: 編碼方式轉換成另一個編碼方式


using System;
using System.Text;
 
namespace ConvertExample
{
   class ConvertExampleClass
   {
      static void Main()
      {
         string unicodeString = "This string contains the unicode character Pi(\u03a0)";
 
         // Create two different encodings.
         Encoding ascii = Encoding.ASCII;
         Encoding unicode = Encoding.Unicode;
 
         // Convert the string into a byte[].
         byte[] unicodeBytes = unicode.GetBytes(unicodeString);
 
         // Perform the conversion from one encoding to the other.
         byte[] asciiBytes = Encoding.Convert(unicode, ascii, unicodeBytes);
            
         // Convert the new byte[] into a char[] and then into a string.
         // This is a slightly different approach to converting to illustrate
         // the use of GetCharCount/GetChars.
         char[] asciiChars = new char[ascii.GetCharCount(asciiBytes, 0, asciiBytes.Length)];
         ascii.GetChars(asciiBytes, 0, asciiBytes.Length, asciiChars, 0);
         string asciiString = new string(asciiChars);
 
         // Display the strings created before and after the conversion.
         Console.WriteLine("Original string: {0}", unicodeString);
         Console.WriteLine("Ascii converted string: {0}", asciiString);
      }
   }
}



以上資料來源: http://msdn.microsoft.com/zh-tw/library/system.text.encoding(v=vs.80)

沒有留言:

張貼留言