6

通常、バイト ストリームから文字を読み取るには、StreamReader を使用します。この例では、無限ストリームから「\r」で区切られたレコードを読み取っています。

using(var reader = new StreamReader(stream, Encoding.UTF8))
{
    var messageBuilder = new StringBuilder();
    var nextChar = 'x';
    while (reader.Peek() >= 0)
    {
        nextChar = (char)reader.Read()
        messageBuilder.Append(nextChar);

        if (nextChar == '\r')
        {
            ProcessBuffer(messageBuilder.ToString());
            messageBuilder.Clear();
        }
    }
}

問題は、StreamReader の内部バッファーが小さいことです。そのため、コードが「レコードの終わり」区切り文字 (この場合は「\r」) を待機している場合、StreamReader の内部バッファーがフラッシュされるまで待機する必要があります (通常、より多くのバイトがあるため)。到着しました)。

この代替実装は、シングルバイト UTF-8 文字では機能しますが、マルチバイト文字では失敗します。

int byteAsInt = 0;
var messageBuilder = new StringBuilder();
while ((byteAsInt = stream.ReadByte()) != -1)
{
    var nextChar = Encoding.UTF8.GetChars(new[]{(byte) byteAsInt});
    Console.Write(nextChar[0]);
    messageBuilder.Append(nextChar);

    if (nextChar[0] == '\r')
    {
        ProcessBuffer(messageBuilder.ToString());
        messageBuilder.Clear();
    }
}

マルチバイト文字で動作するようにこのコードを変更するにはどうすればよいですか?

4

4 に答える 4

10

Encoding.UTF8.GetChars完全なバッファを変換するように設計されているのではなく、のインスタンスを取得してDecoderそのメンバーメソッドを繰り返し呼び出すと、の内部バッファをGetChars使用してDecoder、1つの呼び出しの終わりから次の呼び出しまでの部分的なマルチバイトシーケンスを処理します。

于 2012-07-26T14:48:14.113 に答える
2

ストリーム リーダーの ReadLine メソッドを使用していない理由がわかりません。ただし、そうしない正当な理由がある場合でも、デコーダーで GetChars を繰り返し呼び出すのは非効率的であるように思えます。'\r' のバイト表現がマルチバイト シーケンスの一部ではないという事実を利用しないのはなぜですか? (マルチバイト シーケンスのバイトは 127 より大きい必要があります。つまり、最上位ビットが設定されています。)

var messageBuilder = new List<byte>();

int byteAsInt;
while ((byteAsInt = stream.ReadByte()) != -1)
{
    messageBuilder.Add((byte)byteAsInt);

    if (byteAsInt == '\r')
    {
        var messageString = Encoding.UTF8.GetString(messageBuilder.ToArray());
        Console.Write(messageString);
        ProcessBuffer(messageString);
        messageBuilder.Clear();
    }
}
于 2012-07-26T22:54:23.017 に答える