(In .NET) Ich habe willkürliche Binärdaten in einem Byte [] (ein Bild zum Beispiel) gespeichert. Jetzt muss ich diese Daten in einer Zeichenfolge speichern (ein "Kommentar" -Feld einer alten API). Gibt es eine Standardtechnik für packen diese Binärdaten in eine Zeichenkette ? Mit "packen" meine ich, dass bytes.Length / 2 etwa gleich groß ist wie packed.Length ; weil zwei Bytes mehr oder weniger ein einzelnes Zeichen sind.
Die zwei "offensichtlichen" Antworten erfüllen nicht alle Kriterien:
%Vor%verwendet die Zeichenkette nicht sehr effizient, da nur 64 Zeichen von ungefähr 60.000 Zeichen verwendet werden (mein Speicher ist ein System.String ). Geht mit
%Vor%verwendet die Zeichenfolge besser, funktioniert jedoch nicht für Daten, die ungültige Unicode-Zeichen enthalten (z. B. nicht übereinstimmende Ersatzpaare). Dieser MSDN-Artikel zeigt diese genaue (schlechte) Technik.
Schauen wir uns ein einfaches Beispiel an:
%Vor%In diesem Fall sind Bytes und utf16_bytes identisch, weil die ursprünglichen Bytes eine UTF-16-Zeichenfolge waren. Wenn Sie die gleiche Prozedur mit der base64-Codierung ausführen, erhalten Sie ein Array mit 16 Elementen base64_bytes .
Wiederholen Sie den Vorgang mit ungültigen UTF-16-Daten:
%Vor%Sie werden feststellen, dass utf16_bytes nicht mit den ursprünglichen Daten übereinstimmt.
Ich habe Code geschrieben, der U + FFFD als Escape vor ungültigen Unicode-Zeichen verwendet. es funktioniert, aber ich würde gerne wissen, ob es eine Standard-Technik gibt, als etwas, das ich mir alleine ausgedacht habe. Ganz zu schweigen von der Tatsache, dass ich catch in DecoderFallbackException nicht als Möglichkeit zur Erkennung ungültiger Zeichen empfinde.
Ich denke, Sie könnten dies als "Basis-BMP" oder "Basis-UTF-16" -Kodierung bezeichnen (unter Verwendung aller Zeichen in der Unicode Basic Multilingual Plane). Ja, im Idealfall würde ich Shawn Steeles Rat befolgen und weitergeben byte [] .
Bearbeiten base16k looks noch besser. Jim Beveridge hat eine Implementierung .
Ich bin nach dem Lesen Ihrer Frage auf Base16k gestoßen. Nicht streng ein Standard, aber es scheint gut zu funktionieren und war einfach genug, um in C # zu implementieren.
Darf ich vorschlagen, dass Sie base64 verwenden? Es ist möglicherweise nicht der effizienteste Weg, dies zu tun, aber es hat seine Vorteile:
Denken Sie zunächst daran, dass Unicode nicht 16 Bits bedeutet. Die Tatsache, dass System.String intern UTF-16 verwendet, ist weder hier noch dort. Unicode-Zeichen sind abstrakt - sie erhalten nur Bit-Darstellungen durch Kodierungen.
Sie sagen "mein Speicher ist ein System.String" - wenn das der Fall ist, können Sie nicht über Bits und Bytes sprechen, nur Unicode-Zeichen. System.String hat sicherlich seine eigene interne Kodierung, aber (theoretisch) könnte das anders sein.
Wenn Sie außerdem glauben, dass die interne Darstellung von System.String für Base64-codierte Daten zu speicherineffizient ist, warum machen Sie sich dann auch keine Gedanken über lateinische / westliche Zeichenfolgen?
Wenn Sie binäre Daten in einem System.String speichern möchten, benötigen Sie eine Zuordnung zwischen Sammlungen von Bits und Zeichen.
Option A: Es gibt eine vorgefertigte Version in Form der Base64-Kodierung. Wie Sie bereits erwähnt haben, codiert dies sechs Datenbits pro Zeichen.
Option B: Wenn Sie mehr Bits pro Zeichen packen möchten, müssen Sie ein Array (oder eine Codierung) von 128, 256, 512 usw. Unicode-Zeichen erstellen und 7, 8, 9 usw. Bits packen von Daten pro Zeichen. Diese Zeichen müssen echte Unicode-Zeichen sein.
Um Ihre Frage einfach zu beantworten, ja es gibt einen Standard, es ist Base64-Codierung.
Ist das ein echtes Problem? Haben Sie Perf-Daten, um Ihre Idee zu unterstützen, Base64 nicht zu verwenden?
Hier ist eine C # -Version von Jim Beveridges C ++ Implementierung :
%Vor%Sie könnten die Binärdaten als UTF-8b . Die UTF-8b-Kodierung geht davon aus, dass es sich bei den Bytes um UTF-8-Multibyte-Sequenzen handelt, hat aber eine Fallback-Kodierung für Dinge, die es nicht gibt.
Ich habe mich mit direkten Char-Arrays herumalbern lassen, und Ihr einziger fehlgeschlagener Fall funktioniert mit meiner Implementierung. Der Code wurde gut getestet: also machen Sie zuerst Ihre Tests.
Sie könnten dies beschleunigen, indem Sie unsicheren Code verwenden. Aber ich bin sicher, UnicodeEncoding ist genauso langsam (wenn nicht langsamer).
%Vor%Hier ist ein Testcode:
%Vor%Der Test funktioniert, aber Sie müssen ihn mit Ihrer API-Funktion testen.
Es gibt eine andere Möglichkeit, diese Einschränkung zu umgehen: obwohl ich nicht sicher bin, wie gut es funktionieren würde.
Zuerst müssen Sie herausfinden, welche Art von String der API-Aufruf erwartet - und wie die Struktur dieser Zeichenfolge ist. Wenn ich ein einfaches Beispiel nehme, betrachten wir die .Net-Zeichenkette:
Fügen Sie Ihrem API-Aufruf eine Überladung hinzu:
%Vor%Wenn Sie die Byte-Version aufrufen müssen, können Sie Folgendes tun:
%Vor%