2010-12-10 18 views
37

Ich habe ein Problem mit der UTF8-Codierung in meiner asp.net mvc 2-Anwendung in C#. Ich versuche, Benutzer eine einfache Textdatei aus einer Zeichenfolge herunterladen. Ich versuche Byte-Array mit der folgenden Zeile zu erhalten:Wie GetBytes() in C# mit UTF8-Codierung mit BOM?

var x = Encoding.UTF8.GetBytes(csvString);

aber wenn ich es zum Download zur Rückkehr mit:

return File(x, ..., ...);

ich eine Datei erhalten, die ohne BOM ist so ich don Es werden keine kroatischen Zeichen richtig angezeigt. Dies liegt daran, dass mein Byte-Array nach der Codierung keine Stückliste enthält. Ich habe versucht, diese Bytes manuell einzufügen und dann erscheint es korrekt, aber das ist nicht der beste Weg, es zu tun.

Ich habe auch versucht, erstellen UTF8Encoding-Klasse-Instanz und übergibt einen booleschen Wert (True) zu seinem Konstruktor, um Stückliste, aber es funktioniert auch nicht.

Jeder hat eine Lösung? Vielen Dank!

Antwort

91

Versuchen wie folgt aus:

public ActionResult Download() 
{ 
    var data = Encoding.UTF8.GetBytes("some data"); 
    var result = Encoding.UTF8.GetPreamble().Concat(data).ToArray(); 
    return File(result, "application/csv", "foo.csv"); 
} 

Der Grund hierfür ist, dass der UTF8Encoding Konstruktor, der einen Booleschen Parameter nimmt nicht tut, was man erwarten würde:

byte[] bytes = new UTF8Encoding(true).GetBytes("a"); 

Das resultierende Array eine einzelne enthalten würde Byte mit dem Wert 97. Es gibt keine Stückliste, da UTF8 keine Stückliste benötigt.

+1

Funktioniert wie ein Charme, danke! :) –

+2

Danke! Ich bin verrückt geworden mit meinen Sonderzeichen, die nicht in Excel CSV funktionieren :) –

+1

Der Klarheit halber ist 'Encoding.UTF8' äquivalent zu' new UTF8Encoding (true) '. Der Parameter steuert, ob 'GetPreamble()' eine Stückliste ausgeben wird. – Stijn

2

UTF-8 benötigt keine Stückliste, da es sich um eine Folge von 1-Byte-Wörtern handelt. UTF-8 = UTF-8BE = UTF-8LE.

Im Gegensatz dazu benötigt UTF-16 eine BOM am Anfang des Streams, um festzustellen, ob der Rest des Streams UTF-16BE oder UTF-16LE ist, weil UTF-16 eine Folge von 2-Byte-Wörtern ist Die Stückliste gibt an, ob die Bytes in den Wörtern BE oder LE sind. Das Problem liegt nicht in der Encoding.UTF8 Klasse. Das Problem liegt bei jedem Programm, mit dem Sie die Dateien anzeigen.

+1

UTF-8 ist eine Codierung mit variabler Breite. Es erfordert nur 1 Byte zum Codieren von ASCII-Zeichen, aber andere Codepunkte verwenden mehrere Bytes. –

+2

Die mit mehreren Bytes codierten Codepunkte haben eine vordefinierte Reihenfolge (basierend auf der Big-Endian-Darstellung "U +"). Da UTF8 jedoch als ein Strom von Bytes dargestellt wird (und nicht als ein Strom von Wörtern oder dwörtern, die selbst als eine Folge von Bytes dargestellt sind), gilt das Konzept der Endianz nicht. Endianness ist auf die Darstellung von 16-, 32-, 64-, 128-Bit-Ganzzahlen als Bytes anwendbar, nicht auf die Darstellung von Codepunkten als Bytes. – yfeldblum

+0

Entschuldigung, ich dachte, du beziehst dich auf die Speicherung von Codepoints mit dem Ausdruck "Sequenz von 1 Byte Wörtern". Danke für die Klarstellung. +1 für deine Antwort und deinen Kommentar. –

-1

Denken Sie daran, dass .NET-Zeichenfolgen alle unicode sind, während sie im Speicher bleiben. Wenn Sie also Ihren csvString korrekt mit dem Debugger sehen können, besteht das Problem darin, die Datei zu schreiben.

Meiner Meinung nach sollten Sie eine FileResult mit der gleichen Codierung wie die Dateien zurückgeben. Versuchen Sie, die Rückkehr Datei-Codierung Einstellung

4

Ich habe eine einfache Erweiterung beliebige Zeichenfolge in jeder Codierung seine Darstellung von Byte-Array zu konvertieren, wenn es in eine Datei oder einen Stream geschrieben wird:

public static class StreamExtensions 
{ 
    public static byte[] ToBytes(this string value, Encoding encoding) 
    { 
     using (var stream = new MemoryStream()) 
     using (var sw = new StreamWriter(stream, encoding)) 
     { 
      sw.Write(value); 
      sw.Flush(); 
      return stream.ToArray(); 
     } 
    } 
} 

Verbrauch:

stringValue.ToBytes(Encoding.UTF8) 

Dies funktioniert auch für andere Codierungen wie UTF-16, die die Stückliste erfordert.

+0

Dies ist eigentlich eine sehr nützliche Problemumgehung. Die Verwendung eines "StreamWriter", mit Codierung, löste mein unmittelbares Problem und erlaubte das Öffnen meiner Datei mit Excel 2013. –

Verwandte Themen