2017-07-23 2 views
2

Heute sah ich eine Frage mit Code wie folgt:Ist es sicher, Bytes mit UTF8-Codierung in Zeichenfolge zu konvertieren?

var accumulator = ""; 
var buffer = new byte[8192]; 
while (true) 
{ 
    var readed = stream.Read(buffer, 0, buffer.Length); 
    accumulator += Encoding.UTF8.GetString(buffer, 0, readed); 
    if (readed < buffer.Length) 
     break; 
} 
var result = Encoding.UTF8.GetBytes(accumulator); 

Ich weiß, dass dieser Code ineffizient ist, aber tut es sicher? Gibt es eine Byte-Sequenz, die das Ergebnis bricht?

+2

Alles, was einen Codepunkt über eine 8192-Byte-Grenze aufteilt, wird fehlschlagen, ja. Warum als UTF-8 entschlüsseln, um es sofort neu zu codieren? – Ryan

+3

Nein, es ist nicht sicher. Besser wäre 'accumulate = new StreamReader (stream, Encoding.UTF8) .ReadToEnd()' –

Antwort

6

Der Code ist offensichtlich defekt; Wenn dies als Antwort vorgeschlagen wurde, sollten Sie den Fehler dem Autor zur Kenntnis bringen.

UTF-8-Sequenzen können offensichtlich mehr als ein Byte sein. Wenn eine Sequenz mit mehreren Bytes am Ende des aktuellen Puffers beginnt und am Anfang des folgenden Puffers fortgesetzt wird, ist die Übersetzung jedes Puffers in eine Zeichenfolge falsch.

+0

"wurde als Antwort vorgeschlagen" - nein, dieser Code stammt aus Frage. Aus Ihrer Antwort habe ich einen möglichen Fehler in diesem Ansatz verstanden. Danke –

1

Der sichere Weg dazu ist die Verwendung eines Stateful-UTF8-Decoders, den Sie unter Encoding.UTF8.GetDecoder() erhalten.

Der statusbehaftete Decoder speichert intern Bytes, die einer unvollständigen Multi-Byte-Sequenz entsprechen. Wenn Sie das nächste Mal mehr Bytes geben, wird die Sequenz beendet und die entschlüsselten Zeichen aus der Sequenz zurückgegeben.

Im Folgenden finden Sie ein Beispiel für die Verwendung. In meiner Implementierung verwende ich einen char[] Puffer, der so bemessen ist, dass wir immer genug Platz haben, um eine vollständige Umwandlung von X Byte zu speichern. Auf diese Weise führen wir nur zwei Speicherzuordnungen aus, um einen gesamten Stream zu lesen.

public static string ReadStringFromStream(Stream stream) 
{ 
    // --- Byte-oriented state --- 
    // A nice big buffer for us to use to read from the stream. 
    byte[] byteBuffer = new byte[8192]; 

    // --- Char-oriented state --- 
    // Gets a stateful UTF8 decoder that holds onto unused bytes when multi-byte sequences 
    // are split across multiple byte buffers. 
    var decoder = Encoding.UTF8.GetDecoder(); 

    // Initialize a char buffer, and make it large enough that it will be able to fit 
    // a full reads-worth of data from the byte buffer without needing to be resized. 
    char[] charBuffer = new char[Encoding.UTF8.GetMaxCharCount(byteBuffer.Length)]; 

    // --- Output --- 
    StringBuilder stringBuilder = new StringBuilder(); 

    // --- Working state --- 
    int bytesRead; 
    int charsConverted; 
    bool lastRead = false; 

    do 
    { 
     // Read a chunk of bytes from our stream. 
     bytesRead = stream.Read(byteBuffer, 0, byteBuffer.Length); 

     // If we read 0 bytes, we hit the end of stream. 
     // We're going to tell the converter to flush, and then we're going to stop. 
     lastRead = (bytesRead == 0); 

     // Convert the bytes into characters, flushing if this is our last conversion. 
     charsConverted = decoder.GetChars( 
      byteBuffer, 
      0, 
      bytesRead, 
      charBuffer, 
      0, 
      lastRead 
     ); 

     // Build up a string in a character buffer. 
     stringBuilder.Append(charBuffer, 0, charsConverted); 
    } 
    while(lastRead == false); 

    return stringBuilder.ToString(); 
} 
+1

Keine Notwendigkeit, das Rad neu zu erfinden (vorausgesetzt, es funktioniert), siehe "LB" Kommentar – EZI

+0

@ EZI - Sicher, aber dies zeigt, wie es geht, und damit gibt Ihnen etwas, das Sie an Ihre Situation anpassen können wenn Sie nicht bis zum Ende des Streams lesen möchten oder andere Anforderungen haben. Nichts ist falsch daran, den Vorhang ein wenig zurückzuziehen, hin und wieder. – antiduh

Verwandte Themen