2012-07-26 8 views
6

通常、バイトストリームから文字を読み取るには、StreamReaderを使用します。この例では、無限のストリームから '\ r'で区切られたレコードを読んでいます。無限のバイトストリームからUTF-8文字を読み取る方法 - C#

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をの内部バッファまで待たなければなりません(通常はより多くのバイトが到着したため)フラッシュされます。

この代替実装は、1バイトの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(); 
    } 
} 

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

+0

はタイトルが言うように変更すべきではありません、マルチバイト文字またはUTF-16文字の代わりに、 UTF-8?誤解を招くようです。 –

+1

@TimS。 UTF-8文字は1バイト以上にすることができます。 – Iridium

+0

@TimS。どういう意味ですか?マルチバイトUTF-8文字は自動的にUTF-16文字になりません。 [Wiki](http://en.wikipedia.org/wiki/UTF-8#Description)。 – CodeCaster

答えて

9

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

+0

リチャードに感謝します。実装については私の答えを見てください。 –

5

リチャードのおかげで、私は今、無限のストリームリーダーが動作しています。彼が説明したように、トリックはDecoderインスタンスを使用し、そのGetCharsメソッドを呼び出すことです。私はマルチバイトの日本語のテキストでそれをテストし、それは正常に動作します。

int byteAsInt = 0; 
var messageBuilder = new StringBuilder(); 
var decoder = Encoding.UTF8.GetDecoder(); 
var nextChar = new char[1]; 

while ((byteAsInt = stream.ReadByte()) != -1) 
{ 
    var charCount = decoder.GetChars(new[] {(byte) byteAsInt}, 0, 1, nextChar, 0); 
    if(charCount == 0) continue; 

    Console.Write(nextChar[0]); 
    messageBuilder.Append(nextChar); 

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

あなたは、ストリームリーダーの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(); 
    } 
} 
+0

待って、ストリームでバイト単位で読み込み、バイトのリストの中に入れ、そのリストからバイト配列を構築し、 'Encoding.GetString'を呼び出すと、デコーダで' GetChars'を非効率的に呼び出すと真剣に言いますか? ?あなたが小さな1つの大きなパフォーマンスの問題を逃したように見えます:) ...ああ、私はOPが同じことをしたのを見る。気にしないで。 – Luaan

関連する問題