使用System.Text.Decoder類來處理“流文本”

何爲“流文本”? 他就像“流媒體”,衆所周知“流媒體”可以邊傳送數據邊將已接收的不完整的數據預覽給接收方。“流文本”亦如此。
數據傳輸中的數據並不會按期望以一個整體直接被接收的,尤其是數據量比較大的情況(或者接收方接收速度有限的情況),都會使數據被分割成一塊一塊的形式傳給接收方的。這個數據塊的邊界是沒有任何規律的,因此所謂“流xx”模式實現的一大難點就是怎樣把接收到的數據碎片正確分析並給用戶提供即時預覽。

.NET中有System.Text.Decoder類前來幫忙!

在.NET下,一般情況下將字節數組轉換成字符串的方法是使用Encoding類的成員函數,但是隻有在數據是全部完整的字符編碼纔可以,遇到不完整的數據碎片,Encoding類解析結果中會有亂碼。
這裏就得用到System.Text.Decoder類,同Encoding類一樣,它可以將字節數組轉換成文字,不過他有一個獨一無二的特點,他可以把後面無法識別的編碼緩存起來,等下一批數據進入後,先把緩存的數據加在前面再解析。這恰恰是“流文本”所需要的!
一般情況下使用Decoder類的GetCharCountGetChars方法就可以滿足我們所說的功能,用法和Encoding類的相應方法類似,這裏就不再多介紹了。

另外爲了不介入其他複雜的概念且方便理解,代碼上沒有用System.Net命名空間的類來做一些真的網絡流傳輸,我們就簡簡單單用FileStream,隨機從Stream中讀一段連續字節來模擬數據傳輸中的不確定數據塊,接着每接收到一部分數據塊,程序試圖給出預覽。

static Random random = new Random(Environment.TickCount);

public static void Main()
{
    //臨時文件
    string path = Path.GetTempFileName();
    //使用不加BOM的UTF32寫入字符串ABCDEFG 我你他 123456789 Mgen
    File.WriteAllText(path, "ABCDEFG 我你他 123456789 Mgen", new UTF32Encoding(false, false));
    
    //創建Decoder對象
    Decoder dec = Encoding.UTF32.GetDecoder();

    using (FileStream fs = File.OpenRead(path))
    {
        byte[] buffer;
        int size;
        //隨機讀取一部分,並用Decoder嘗試輸出可以得到的文字
        while ((size = GetRandomPart(fs, out buffer)) > 0)
        {
            char[] chars = new char[dec.GetCharCount(buffer, 0, buffer.Length)];
            dec.GetChars(buffer, 0, buffer.Length, chars, 0);
            if (chars.Length != 0)
            {
                Console.Write("{0,-20}", new string(chars).Replace(" ", "<空格>"));
                Console.Write("數據塊:");
                PrintBytes(buffer, size);
            }
        }
    }
}

//輸出字節數組
static void PrintBytes(byte[] bytes, int len)
{
    for (int i = 0; i < len; i++)
        Console.Write("{0:X2} ", bytes[i]);
    Console.WriteLine();
}

//隨機讀取一塊數據
static int GetRandomPart(Stream s, out byte[] buffer)
{
    buffer = new byte[random.Next(1, 12)];
    return s.Read(buffer, 0, buffer.Length);
}

一種輸出(因爲每次輸出結果隨機):

AB                  數據塊:41 00 00 00 42 00 00 00 43 00
CD                  數據塊:00 00 44 00 00 00 45 00 00
E                   數據塊:00 46 00 00
F                   數據塊:00 47
G<空格>               數據塊:00 00 00 20 00 00 00
我你                  數據塊:00 00 60 4F 00 00 D6 4E 00
他<空格>               數據塊:00 20 00 00 00 31 00 00
1                   數據塊:00 32 00 00
2                   數據塊:00 33 00
345                 數據塊:00 00 34 00 00 00 35 00 00 00 36
678                 數據塊:00 00 00 37 00 00 00 38 00 00 00
9<空格>               數據塊:39 00 00 00 20 00 00 00 4D 00 00
M                   數據塊:00 67 00
ge                  數據塊:00 00 65 00 00 00 6E 00 00
n                   數據塊:00

不錯,Decoder可以很好得預覽出每一段接受的數據塊,即使這些數據塊是不完整的(並不是某些字符的對應編碼值是在一個數據塊裏的)
如果你把上面的DecoderGetCharCountGetChars方法改成Encoding類的對應方法,結果會是一片亂碼(只有少數字符由於隨機數據塊較規則會被正確解析,不過只有很少)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章