2012-07-26 8 views
6

Normalde, bir bayt akışından karakterleri okumak için bir StreamReader kullanıyorsunuz. Bu örnekte, sonsuz bir akıştan '\ r' ile sınırlandırılmış kayıtları okuyorum.UTF-8 karakterlerini sonsuz bayt akışından nasıl okuyorsunuz? 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(); 
     } 
    } 
} 

sorunu (bu durumda '\ r') sınırlayıcı bir 'kayıt sonu' bekliyor kod sahip olduğu StreamReader iç tampon kadar beklemek eğer öyleyse StreamReader, küçük bir iç tampon olmasıdır kızardı (genellikle daha fazla bayt geldiği için).

Bu alternatif uygulama, tek bayt UTF-8 karakterleri için çalışır, ancak çok baytlı karakterler üzerinde başarısız olur.

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(); 
    } 
} 

Bu kodu, çok baytlı karakterlerle çalışacak şekilde nasıl değiştirebilirim? arka arkaya, tam tampon dönüştürmek Decoder bir örneğini elde etmek için tasarlanmış ve

+0

başlık söylemek değiştirilemez olmamalı multi-byte veya UTF-16 karakter yerine UTF-8? Yanıltıcı görünüyor. –

+1

@TimS. UTF-8 karakterleri tek bir bayttan daha fazlası olabilir. – Iridium

+0

@TimS. ne demek istiyorsun? Çok baytlı bir UTF-8 karakteri, otomatik olarak bir UTF-16 karakterine dönüşmez. [Wiki] (http://en.wikipedia.org/wiki/UTF-8#Description). – CodeCaster

cevap

9

yerine Encoding.UTF8.GetChars üye yöntemi GetChars bu bir ucundan kısmi bir çoklu bit dizileri ele Decoder dahili tampon faydalanmak çağırmak sonraki çağrı.

+0

Teşekkürler Richard, bu harika çalışıyor. Uygulamam için cevabımı görün. –

5

Richard sayesinde, artık sonsuz bir akış okuyucu var. Açıkladığı gibi, hile bir Decoder örneğini kullanmak ve GetChars yöntemini çağırmaktır. Ben multi-byte Japonca metin ile test ettik ve iyi çalışıyor.

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

Neden akış okuyucunun ReadLine yöntemini kullanmıyorsunuz anlamıyorum. Bununla birlikte, iyi bir neden olmasa da, yine de, yine de, GetChars'ı kod çözücüde tekrar tekrar çağırmanın verimsiz olduğunu düşünüyorum. Neden '\ r' bayt temsilinin çoklu bayt dizisinin bir parçası olamayacağı gerçeğinden yararlanmıyorsunuz? (A multi-byte sırayla Bayt 127 daha büyük olmalıdır;. Yani onlar en yüksek biti ayarlanmamış)

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

Bekle, bayt-by-byte akışını okurken, byte-by-byte akışını okurken ve daha sonra bu listeden bir bayt dizisi oluşturarak ve 'Encoding.GetString' işlevini çağırarak, kod çözücüde" GetChars "işlevini çağırmaktan ciddiye alıyor musunuz? ? Küçük olan için büyük bir performans sorununu kaçırmışsınız gibi görünüyor. :), OP'nin de aynı şeyi yaptığını görüyorum. Boşver. – Luaan