Wie konvertiere ich ein string
in ein byte[]
in .NET (C #), ohne manuell eine bestimmte Codierung anzugeben?
Ich werde den String verschlüsseln. Ich kann es verschlüsseln, ohne es zu konvertieren, aber ich möchte immer noch wissen, warum das Codieren hier zum Einsatz kommt.
Warum sollte auch die Codierung berücksichtigt werden? Kann ich nicht einfach herausfinden, in welchen Bytes der String gespeichert wurde? Warum besteht eine Abhängigkeit von Zeichenkodierungen?
Wie Sie bereits erwähnt haben, besteht Ihr Ziel einfach darin, "zu ermitteln, in welchen Bytes die Zeichenfolge gespeichert wurde" .
(Und natürlich, um den String aus den Bytes rekonstruieren zu können.)
Mach das einfach stattdessen:
static byte[] GetBytes(string str)
{
byte[] bytes = new byte[str.Length * sizeof(char)];
System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
return bytes;
}
// Do NOT use on arbitrary bytes; only use on GetBytes's output on the SAME system
static string GetString(byte[] bytes)
{
char[] chars = new char[bytes.Length / sizeof(char)];
System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
return new string(chars);
}
Solange Ihr Programm (oder andere Programme) nicht versucht die Bytes zu interpretieren , was Sie offensichtlich nicht erwähnt haben, was Sie vorhaben, dann gibt es nichts falsch mit diesem Ansatz! Die Sorge um Kodierungen macht Ihr Leben nur ohne wirklichen Grund komplizierter.
Es wird genauso codiert und decodiert, da Sie nur die Bytes betrachten.
Wenn Sie jedoch eine bestimmte Kodierung verwendet hätten, hätten Sie Probleme beim Kodieren/Dekodieren ungültiger Zeichen.
Dies hängt von der Kodierung Ihres Strings ab ( ASCII , TF-8 , ...).
Zum Beispiel:
byte[] b1 = System.Text.Encoding.UTF8.GetBytes (myString);
byte[] b2 = System.Text.Encoding.ASCII.GetBytes (myString);
Ein kleines Beispiel, warum Codierung wichtig ist:
string pi = "\u03a0";
byte[] ascii = System.Text.Encoding.ASCII.GetBytes (pi);
byte[] utf8 = System.Text.Encoding.UTF8.GetBytes (pi);
Console.WriteLine (ascii.Length); //Will print 1
Console.WriteLine (utf8.Length); //Will print 2
Console.WriteLine (System.Text.Encoding.ASCII.GetString (ascii)); //Will print '?'
ASCII ist einfach nicht für den Umgang mit Sonderzeichen gerüstet.
Intern verwendet das .NET-Framework TF-16 , um Zeichenfolgen darzustellen. Wenn Sie also nur die genauen von .NET verwendeten Bytes abrufen möchten, verwenden Sie System.Text.Encoding.Unicode.GetBytes (...)
.
Weitere Informationen finden Sie unter Zeichencodierung in .NET Framework (MSDN).
Die akzeptierte Antwort ist sehr, sehr kompliziert. Verwenden Sie dazu die mitgelieferten .NET-Klassen:
const string data = "A string with international characters: Norwegian: ÆØÅæøå, Chinese: 喂 谢谢";
var bytes = System.Text.Encoding.UTF8.GetBytes(data);
var decoded = System.Text.Encoding.UTF8.GetString(bytes);
Erfinden Sie das Rad nicht neu, wenn Sie nicht müssen ...
BinaryFormatter bf = new BinaryFormatter();
byte[] bytes;
MemoryStream ms = new MemoryStream();
string orig = "喂 Hello 谢谢 Thank You";
bf.Serialize(ms, orig);
ms.Seek(0, 0);
bytes = ms.ToArray();
MessageBox.Show("Original bytes Length: " + bytes.Length.ToString());
MessageBox.Show("Original string Length: " + orig.Length.ToString());
for (int i = 0; i < bytes.Length; ++i) bytes[i] ^= 168; // pseudo encrypt
for (int i = 0; i < bytes.Length; ++i) bytes[i] ^= 168; // pseudo decrypt
BinaryFormatter bfx = new BinaryFormatter();
MemoryStream msx = new MemoryStream();
msx.Write(bytes, 0, bytes.Length);
msx.Seek(0, 0);
string sx = (string)bfx.Deserialize(msx);
MessageBox.Show("Still intact :" + sx);
MessageBox.Show("Deserialize string Length(still intact): "
+ sx.Length.ToString());
BinaryFormatter bfy = new BinaryFormatter();
MemoryStream msy = new MemoryStream();
bfy.Serialize(msy, sx);
msy.Seek(0, 0);
byte[] bytesy = msy.ToArray();
MessageBox.Show("Deserialize bytes Length(still intact): "
+ bytesy.Length.ToString());
Sie müssen die Codierung berücksichtigen, da 1 Zeichen durch 1 oder mehr Bytes (bis zu ca. 6) dargestellt werden kann und verschiedene Codierungen behandelt werden diese Bytes unterschiedlich.
Joel hat ein Posting dazu:
Dies ist eine beliebte Frage. Es ist wichtig zu verstehen, was der Fragesteller fragt und was nicht das wahrscheinlich häufigste Bedürfnis ist. Um den Missbrauch des Codes zu verhindern, wenn er nicht benötigt wird, habe ich den späteren zuerst beantwortet.
Jeder String hat einen Zeichensatz und eine Kodierung. Wenn Sie ein System.String
-Objekt in ein Array von System.Byte
konvertieren, verfügen Sie weiterhin über einen Zeichensatz und eine Codierung. Für die meisten Verwendungszwecke wissen Sie, welchen Zeichensatz und welche Codierung Sie benötigen, und .NET vereinfacht das "Kopieren mit Konvertierung". Wählen Sie einfach die entsprechende aus Encoding
Klasse.
// using System.Text;
Encoding.UTF8.GetBytes(".NET String to byte array")
Die Konvertierung muss möglicherweise Fälle behandeln, in denen der Zielzeichensatz oder die Zielcodierung kein Zeichen in der Quelle unterstützt. Sie haben einige Möglichkeiten: Ausnahme, Ersetzung oder Überspringen. Standardmäßig wird ein '?'.
// using System.Text;
var text = Encoding.ASCII.GetString(Encoding.ASCII.GetBytes("You win €100"));
// -> "You win ?100"
Conversions sind natürlich nicht unbedingt verlustfrei!
Hinweis: Für System.String
ist der Quellzeichensatz Unicode.
Das einzig Verwirrende ist, dass .NET den Namen eines Zeichensatzes für den Namen einer bestimmten Kodierung dieses Zeichensatzes verwendet. Encoding.Unicode
sollte Encoding.UTF16
heißen.
Das ist es für die meisten Verwendungen. Wenn es das ist, was Sie brauchen, hören Sie hier auf zu lesen. Lesen Sie den Spaß Artikel von Joel Spolsky wenn Sie nicht verstehen, was eine Codierung ist.
Nun fragt der Frageautor: "Jeder String wird als Array von Bytes gespeichert, oder? Warum kann ich diese Bytes nicht einfach haben?"
Er will keine Bekehrung.
Aus der C # -Spezifikation :
Die Zeichen- und Zeichenfolgenverarbeitung in C # verwendet Unicode-Codierung. Der Zeichen-Typ repräsentiert eine UTF-16-Code-Einheit und der Zeichen-Typ repräsentiert eine Folge von UTF-16-Code-Einheiten.
Wir wissen also, dass wir das gewünschte Ergebnis erhalten, wenn wir nach der Nullkonvertierung fragen (d. H. Von UTF-16 nach UTF-16):
Encoding.Unicode.GetBytes(".NET String to byte array")
Aber um die Erwähnung von Kodierungen zu vermeiden, müssen wir es anders machen. Wenn ein Zwischendatentyp akzeptabel ist, gibt es hierfür eine konzeptionelle Verknüpfung:
".NET String to byte array".ToCharArray()
Das bringt uns nicht den gewünschten Datentyp, aber Mehrdads Antwort zeigt, wie dieses Char-Array mit BlockCopy in ein Byte-Array konvertiert wird. Dadurch wird die Zeichenfolge jedoch zweimal kopiert! Und es wird auch explizit codierungsspezifischer Code verwendet: der Datentyp System.Char
.
Die einzige Möglichkeit, zu den tatsächlichen Bytes zu gelangen, in denen der String gespeichert ist, ist die Verwendung eines Zeigers. Die Anweisung fixed
ermöglicht die Adressierung von Werten. Aus der C # -Spezifikation:
[Für] einen Ausdruck vom Typ Zeichenfolge ... berechnet der Initialisierer die Adresse des ersten Zeichens in der Zeichenfolge.
Dazu schreibt der Compiler mit RuntimeHelpers.OffsetToStringData
einen Code, der die anderen Teile des String-Objekts überspringt. Um die unformatierten Bytes zu erhalten, erstellen Sie einfach einen Zeiger auf die Zeichenfolge und kopieren Sie die Anzahl der benötigten Bytes.
// using System.Runtime.InteropServices
unsafe byte[] GetRawBytes(String s)
{
if (s == null) return null;
var codeunitCount = s.Length;
/* We know that String is a sequence of UTF-16 codeunits
and such codeunits are 2 bytes */
var byteCount = codeunitCount * 2;
var bytes = new byte[byteCount];
fixed(void* pRaw = s)
{
Marshal.Copy((IntPtr)pRaw, bytes, 0, byteCount);
}
return bytes;
}
Wie @CodesInChaos hervorhob, hängt das Ergebnis von der Endgültigkeit der Maschine ab. Aber der Frageautor kümmert sich nicht darum.
Der erste Teil Ihrer Frage (wie Sie die Bytes erhalten) wurde bereits von anderen beantwortet: Schauen Sie im Namensraum System.Text.Encoding
nach.
Ich werde Ihre nachfolgende Frage beantworten: Warum müssen Sie eine Codierung auswählen? Warum kann man das nicht von der String-Klasse selbst bekommen?
Die Antwort besteht aus zwei Teilen.
Zuallererst sind die Bytes, die intern von der Zeichenfolgenklasse verwendet werden, egal , und wann immer Sie davon ausgehen, dass sie dies tun, führen Sie wahrscheinlich einen Fehler ein.
Befindet sich Ihr Programm vollständig in der .Net-Welt, müssen Sie sich keine Gedanken darüber machen, ob Sie Byte-Arrays für Zeichenfolgen erhalten, selbst wenn Sie Daten über ein Netzwerk senden. Verwenden Sie stattdessen .Net Serialization, um die Daten zu übertragen. Sie kümmern sich nicht mehr um die tatsächlichen Bytes: Der Serialization-Formatierer erledigt dies für Sie.
Was ist andererseits, wenn Sie diese Bytes an einen Ort senden, für den Sie nicht garantieren können, dass sie Daten aus einem serialisierten .Net-Stream abrufen? In diesem Fall müssen Sie sich definitiv um die Codierung kümmern, da sich dieses externe System offensichtlich darum kümmert. Auch hier spielt es keine Rolle, welche internen Bytes von der Zeichenfolge verwendet werden: Sie müssen eine Codierung auswählen, damit Sie diese Codierung auf der empfangenden Seite explizit angeben können, auch wenn es sich um dieselbe Codierung handelt, die intern von .NET verwendet wird.
Ich verstehe, dass Sie in diesem Fall möglicherweise die tatsächlichen Bytes bevorzugen, die in der Zeichenfolgenvariablen im Speicher gespeichert sind, mit der Idee, dass dadurch möglicherweise Arbeit beim Erstellen Ihres Bytestreams gespart wird. Ich sage es Ihnen jedoch, es ist einfach nicht wichtig, um sicherzustellen, dass Ihre Ausgabe am anderen Ende verstanden wird, und um sicherzustellen, dass Sie explizit mit Ihrer Codierung sein müssen . Wenn Sie wirklich mit Ihren internen Bytes übereinstimmen möchten, können Sie bereits die Codierung Unicode
auswählen und diese Leistungsersparnis erzielen.
Das bringt mich zum zweiten Teil ... Auswählen der Unicode
-Codierung is, die .Net anweist, die zugrunde liegenden Bytes zu verwenden. Sie müssen diese Codierung auswählen, da bei Erscheinen von neuem Unicode-Plus die .Net-Laufzeit frei sein muss, um dieses neuere, bessere Codierungsmodell zu verwenden, ohne Ihr Programm zu beschädigen. Aber im Moment (und in absehbarer Zukunft) erhalten Sie alles, was Sie wollen, wenn Sie nur die Unicode-Codierung auswählen.
Es ist auch wichtig zu verstehen, dass Ihre Zeichenfolge neu in wire geschrieben werden muss, und dies erfordert zumindest eine Übersetzung des Bitmusters , auch wenn Sie eine passende Codierung verwenden. Der Computer muss Dinge wie Big vs Little Endian, Netzwerk-Bytereihenfolge, Paketierung, Sitzungsinformationen usw. berücksichtigen.
Um zu demonstrieren, dass Mehrdrads Sound Antwort funktioniert, kann sein Ansatz sogar die ngepaarten Ersatzcharaktere (von denen sich viele gegen meine Antwort gestellt hatten, von denen sich aber alle gleichermaßen schuldig fühlen) beibehalten zB System.Text.Encoding.UTF8.GetBytes
, System.Text.Encoding.Unicode.GetBytes
; diese Codierungsmethoden können beispielsweise die hohen Ersatzzeichen d800
nicht beibehalten, und diese ersetzen nur die hohen Ersatzzeichen durch den Wert fffd
):
using System;
class Program
{
static void Main(string[] args)
{
string t = "爱虫";
string s = "Test\ud800Test";
byte[] dumpToBytes = GetBytes(s);
string getItBack = GetString(dumpToBytes);
foreach (char item in getItBack)
{
Console.WriteLine("{0} {1}", item, ((ushort)item).ToString("x"));
}
}
static byte[] GetBytes(string str)
{
byte[] bytes = new byte[str.Length * sizeof(char)];
System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
return bytes;
}
static string GetString(byte[] bytes)
{
char[] chars = new char[bytes.Length / sizeof(char)];
System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
return new string(chars);
}
}
Ausgabe:
T 54
e 65
s 73
t 74
? d800
T 54
e 65
s 73
t 74
Versuchen Sie das mit System.Text.Encoding.UTF8.GetBytes oder System.Text.Encoding.Unicode.GetBytes , sie ersetzen nur High-Surrogate-Zeichen durch value fffd
Jedes Mal, wenn es eine Bewegung in dieser Frage gibt, denke ich an einen Serialisierer (sei es von Microsoft oder einer Drittanbieter-Komponente), der Zeichenfolgen beibehalten kann, selbst wenn diese nicht gepaarte Ersatzzeichen enthalten. Ich google dies hin und wieder: Serialisierung ungepaartes Ersatzzeichen .NET . Dadurch verliere ich nicht den Schlaf, aber es ist ärgerlich, wenn hin und wieder jemand meine Antwort als fehlerhaft kommentiert, und ihre Antworten sind gleichermaßen fehlerhaft, wenn es um ungepaarte Ersatzcharaktere geht.
Verdammt, Microsoft hätte gerade System.Buffer.BlockCopy
in seinem BinaryFormatter
ツ verwenden sollen
谢谢 谢谢
Versuchen Sie dies, viel weniger Code:
System.Text.Encoding.UTF8.GetBytes("TEST String");
Nun, ich habe alle Antworten gelesen und sie verwendeten Codierung oder eine über Serialisierung, die ungepaarte Ersatzzeichen fallen lässt.
Es ist schlecht, wenn die Zeichenfolge beispielsweise von SQL Server stammt, wo sie aus einem Byte-Array erstellt wurde, in dem beispielsweise ein Kennwort-Hash gespeichert ist. Wenn wir irgendetwas davon löschen, wird ein ungültiger Hash gespeichert, und wenn wir ihn in XML speichern möchten, möchten wir ihn intakt lassen (da der XML-Writer eine Ausnahme für jeden nicht gepaarten Ersatz ablegt, den er findet).
Also verwende ich Base64 Codierung von Byte-Arrays in solchen Fällen, aber hey, im Internet gibt es nur eine Lösung für dieses Problem in C #, und es enthält Fehler und ist nur eine Möglichkeit. Fehler behoben und Prozedur zurückgeschrieben. Hier sind Sie, zukünftige Googler:
public static byte[] StringToBytes(string str)
{
byte[] data = new byte[str.Length * 2];
for (int i = 0; i < str.Length; ++i)
{
char ch = str[i];
data[i * 2] = (byte)(ch & 0xFF);
data[i * 2 + 1] = (byte)((ch & 0xFF00) >> 8);
}
return data;
}
public static string StringFromBytes(byte[] arr)
{
char[] ch = new char[arr.Length / 2];
for (int i = 0; i < ch.Length; ++i)
{
ch[i] = (char)((int)arr[i * 2] + (((int)arr[i * 2 + 1]) << 8));
}
return new String(ch);
}
Erklären Sie auch, warum die Codierung berücksichtigt werden sollte. Kann ich nicht einfach herausfinden, in welchen Bytes die Zeichenfolge gespeichert wurde? Warum diese Abhängigkeit von der Kodierung? !!!
Weil es so etwas wie "die Bytes der Zeichenkette" nicht gibt.
Eine Zeichenfolge (oder allgemeiner ein Text) besteht aus Zeichen: Buchstaben, Ziffern und anderen Symbolen. Das ist alles. Computer wissen jedoch nichts über Charaktere; Sie können nur mit Bytes umgehen. Wenn Sie Text auf einem Computer speichern oder übertragen möchten, müssen Sie die Zeichen daher in Bytes umwandeln. Wie machst du das? Hier kommen Codierungen auf die Bühne.
Eine Kodierung ist nichts anderes als eine Konvention, um logische Zeichen in physikalische Bytes zu übersetzen. Die einfachste und bekannteste Codierung ist ASCII. Sie ist alles, was Sie benötigen, wenn Sie in Englisch schreiben. Für andere Sprachen benötigen Sie umfassendere Codierungen, da derzeit alle Unicode-Varianten die sicherste Wahl sind.
Kurz gesagt, der Versuch, "die Bytes einer Zeichenkette ohne Verwendung von Codierungen zu erhalten", ist so unmöglich wie "einen Text ohne Verwendung einer Sprache zu schreiben".
Übrigens, ich empfehle Ihnen (und allen anderen) nachdrücklich, diese kleine Weisheit zu lesen: Das absolute Minimum, das jeder Softwareentwickler unbedingt, positiv über Unicode und Zeichensätze wissen muss ( Keine Ausreden!)
C # zum Konvertieren eines string
in ein byte
-Array:
public static byte[] StrToByteArray(string str)
{
System.Text.UTF8Encoding encoding=new System.Text.UTF8Encoding();
return encoding.GetBytes(str);
}
Sie können den folgenden Code für die Konvertierung zwischen String- und Byte-Array verwenden.
string s = "Hello World";
// String to Byte[]
byte[] byte1 = System.Text.Encoding.Default.GetBytes(s);
// OR
byte[] byte2 = System.Text.ASCIIEncoding.Default.GetBytes(s);
// Byte[] to string
string str = System.Text.Encoding.UTF8.GetString(byte1);
byte[] strToByteArray(string str)
{
System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
return enc.GetBytes(str);
}
Ich bin nicht sicher, aber ich denke, die Zeichenfolge speichert ihre Informationen als ein Array von Zeichen, was mit Bytes ineffizient ist. Insbesondere lautet die Definition eines Zeichens "Repräsentiert ein Unicode-Zeichen".
nimm dieses beispielbeispiel:
String str = "asdf éß";
String str2 = "asdf gh";
EncodingInfo[] info = Encoding.GetEncodings();
foreach (EncodingInfo enc in info)
{
System.Console.WriteLine(enc.Name + " - "
+ enc.GetEncoding().GetByteCount(str)
+ enc.GetEncoding().GetByteCount(str2));
}
Beachten Sie, dass die Unicode-Antwort in beiden Fällen 14 Byte beträgt, während die UTF-8-Antwort für die erste nur 9 Byte und für die zweite nur 7 Byte beträgt.
Wenn Sie also nur die von der Zeichenfolge verwendeten Bytes verwenden möchten, verwenden Sie einfach Encoding.Unicode
, aber der Speicherplatz wird ineffizient sein.
Mit dem Aufkommen von Span<T>
, das mit C # 7.2 veröffentlicht wurde, ist die kanonische Technik zum Erfassen der zugrunde liegenden Speicherdarstellung einer Zeichenfolge in einem verwalteten Byte-Array wie folgt:
_byte[] bytes = "rubbish_\u9999_string".AsSpan().AsBytes().ToArray();
_
Das Zurückkonvertieren sollte ein Nichtstarter sein, da dies bedeutet, dass Sie die Daten tatsächlich irgendwie interpretieren, aber der Vollständigkeit halber:
_string s;
unsafe
{
fixed (char* f = &bytes.AsSpan().NonPortableCast<byte, char>().DangerousGetPinnableReference())
{
s = new string(f);
}
}
_
Die Namen NonPortableCast
und DangerousGetPinnableReference
sollten das Argument unterstützen, dass Sie dies wahrscheinlich nicht tun sollten.
Beachten Sie, dass für die Arbeit mit _Span<T>
_ das System.Memory NuGet-Paket installiert werden muss.
Unabhängig davon implizieren die tatsächlichen ursprünglichen Fragen- und Folgekommentare, dass der zugrunde liegende Speicher nicht "interpretiert" wird (was meiner Meinung nach bedeutet, dass er nicht geändert oder gelesen wird jenseits der Notwendigkeit, es so zu schreiben, wie es ist), was angibt, dass eine Implementierung der Klasse Stream
verwendet werden sollte, anstatt die Daten überhaupt als Zeichenfolgen zu interpretieren.
Das Hauptproblem besteht darin, dass eine Glyphe in einer Zeichenfolge 32 Bit (16 Bit für einen Zeichencode) benötigt, ein Byte jedoch nur 8 Bit übrig hat. Eine Eins-zu-Eins-Zuordnung ist nur möglich, wenn Sie sich auf Zeichenfolgen beschränken, die nur ASCII Zeichen enthalten. System.Text.Encoding bietet viele Möglichkeiten, eine Zeichenfolge Byte [] zuzuordnen. Sie müssen eine auswählen, die Informationsverlust vermeidet und von Ihrem Client verwendet werden kann, wenn das Byte [] einer Zeichenfolge zugeordnet werden muss .
Utf8 ist eine beliebte Kodierung, sie ist kompakt und nicht verlustbehaftet.
Verwenden:
string text = "string";
byte[] array = System.Text.Encoding.UTF8.GetBytes(text);
Das Ergebnis ist:
[0] = 115
[1] = 116
[2] = 114
[3] = 105
[4] = 110
[5] = 103
Wie konvertiere ich eine Zeichenfolge in ein Byte [] in .NET (C #), ohne manuell eine bestimmte Codierung anzugeben?
Ein Zeichenfolge in .NET stellt Text als Folge von UTF-16-Codeeinheiten dar, sodass die Bytes bereits in UTF-16 im Speicher codiert sind.
Mehrdads Antwort
Sie können Mehrdads Antwort verwenden, es wird jedoch tatsächlich eine Codierung verwendet, da die Zeichen UTF-16 sind. Es ruft ToCharArray auf, das beim Betrachten von der Quelle einen char[]
erstellt und den Speicher direkt dorthin kopiert. Anschließend werden die Daten in ein Byte-Array kopiert, das ebenfalls zugeordnet ist. Unter der Haube werden also die zugrunde liegenden Bytes zweimal kopiert und ein Zeichen-Array zugewiesen, das nach dem Aufruf nicht verwendet wird.
Tom Blodgets Antwort
Tom Blodgets Antwort ist 20-30% schneller als Mehrdad, da der Zwischenschritt des Zuweisens eines char-Arrays und des Kopierens der Bytes übersprungen wird, Sie jedoch die Option /unsafe
verwenden müssen. Wenn Sie absolut keine Codierung verwenden möchten, ist dies der richtige Weg. Wenn Sie Ihr Verschlüsselungs-Login in den Block fixed
einfügen, müssen Sie nicht einmal ein separates Byte-Array zuweisen und die Bytes in dieses kopieren.
Warum sollte auch die Codierung berücksichtigt werden? Kann ich nicht einfach herausfinden, in welchen Bytes die Zeichenfolge gespeichert wurde? Warum besteht eine Abhängigkeit von Zeichenkodierungen?
Weil das der richtige Weg ist. string
ist eine Abstraktion.
Die Verwendung einer Codierung kann zu Problemen führen, wenn Sie Zeichenfolgen mit ungültigen Zeichen haben. Dies sollte jedoch nicht passieren. Wenn Sie Daten mit ungültigen Zeichen in Ihren String bekommen, machen Sie es falsch. Sie sollten wahrscheinlich zunächst ein Byte-Array oder eine Base64-Codierung verwenden.
Wenn Sie System.Text.Encoding.Unicode
verwenden, ist Ihr Code widerstandsfähiger. Sie müssen sich keine Gedanken über die Endianität des Systems machen, auf dem Ihr Code ausgeführt wird. Sie müssen sich keine Sorgen machen, wenn die nächste Version der CLR eine andere interne Zeichencodierung verwendet.
Ich denke, die Frage ist nicht, warum Sie sich um die Kodierung kümmern möchten, sondern warum Sie sie ignorieren und etwas anderes verwenden möchten. Die Codierung soll die Abstraktion einer Zeichenfolge in einer Folge von Bytes darstellen. System.Text.Encoding.Unicode
gibt Ihnen eine kleine Codierung in der Endian-Byte-Reihenfolge und führt jetzt und in Zukunft auf jedem System die gleiche Leistung aus.
Schnellster Weg
public static byte[] GetBytes(string text)
{
return System.Text.ASCIIEncoding.UTF8.GetBytes(text);
}
EDIT wie Makotosan kommentierte, ist dies nun der beste Weg:
Encoding.UTF8.GetBytes(text)
Die Frage von Tom Blodget kommt der Frage von OP am nächsten, die tatsächlich in das Objekt eingeht und die Bytes extrahiert. Ich sage am nächsten, weil es von der Implementierung des String-Objekts abhängt.
"Can't I simply get what bytes the string has been stored in?"
Klar, aber hier tritt der grundlegende Fehler in der Frage auf. Der String ist ein Objekt, das eine interessante Datenstruktur haben könnte. Wir wissen bereits, dass dies der Fall ist, da ungepaarte Ersatzzeichen gespeichert werden können. Es könnte die Länge speichern. Es könnte einen Zeiger auf jedes der 'gepaarten' Ersatzzeichen behalten, was ein schnelles Zählen ermöglicht. Usw. Alle diese zusätzlichen Bytes sind nicht Teil der Zeichendaten.
Was Sie wollen, sind die Bytes jedes Zeichens in einem Array. Und hier kommt die Codierung ins Spiel. Standardmäßig erhalten Sie UTF-16LE. Wenn Sie sich nicht um die Bytes selbst kümmern, können Sie eine beliebige Codierung auswählen, einschließlich der Standardcodierung, und diese später zurückkonvertieren (unter der Annahme, dass dieselben Parameter wie die Standardcodierung, Codepunkte und Fehlerbehebungen verwendet wurden , erlaubte Dinge wie ungepaarte Leihmütterchen usw.
Aber warum überlässt man die "Kodierung" der Magie? Warum nicht die Codierung angeben, damit Sie wissen, welche Bytes Sie erhalten?
"Why is there a dependency on character encodings?"
Codierung (in diesem Kontext) bedeutet einfach die Bytes, die Ihre Zeichenfolge darstellen. Nicht die Bytes des String-Objekts. Sie wollten die Bytes, in denen die Zeichenfolge gespeichert wurde - hier wurde die Frage naiv gestellt. Sie wollten die Zeichenfolgenbytes in einem zusammenhängenden Array, das die Zeichenfolge darstellt, und nicht alle anderen Binärdaten, die ein Zeichenfolgenobjekt möglicherweise enthält.
Was bedeutet, wie ein String gespeichert wird, ist irrelevant. Sie möchten, dass eine Zeichenfolge in Bytes in einem Byte-Array "codiert" wird.
Ich mag die Antwort von Tom Bloget, weil er Sie in Richtung der Richtung "Bytes of the String Object" geführt hat. Es hängt jedoch von der Implementierung ab, und da er sich die Interna ansieht, ist es möglicherweise schwierig, eine Kopie des Strings wiederherzustellen.
Mehrdads Antwort ist falsch, weil sie auf konzeptioneller Ebene irreführend ist. Sie haben immer noch eine Liste mit codierten Bytes. Seine spezielle Lösung ermöglicht es, ungepaarte Ersatzzeichen beizubehalten - dies ist implementierungsabhängig. Seine spezielle Lösung würde die Bytes der Zeichenkette nicht genau erzeugen, wenn GetBytes
die Zeichenkette standardmäßig in UTF-8 zurückliefern würde.
Ich habe es mir anders überlegt (Mehrdads Lösung) - hier werden nicht die Bytes des Strings angezeigt. Vielmehr werden die Bytes des Zeichenarrays abgerufen, das aus der Zeichenfolge erstellt wurde. Unabhängig von der Codierung hat der char-Datentyp in c # eine feste Größe. Dies ermöglicht die Erzeugung eines Byte-Arrays mit konsistenter Länge und die Wiedergabe des Zeichen-Arrays basierend auf der Größe des Byte-Arrays. Wenn die Codierung UTF-8 wäre, aber jedes Zeichen 6 Byte groß wäre, um den größten utf8-Wert aufzunehmen, würde es trotzdem funktionieren. In der Tat spielt die Kodierung des Zeichens keine Rolle.
Es wurde jedoch eine Konvertierung verwendet - jedes Zeichen wurde in ein Feld mit fester Größe (c # - Zeichentyp) eingefügt. Was diese Darstellung ist, spielt jedoch keine Rolle, was technisch die Antwort auf das OP ist. Also - wenn Sie sowieso konvertieren wollen ... Warum nicht "encodieren"?
Sie können folgenden Code verwenden, um string
in byte array
in .NET zu konvertieren
string s_unicode = "abcéabc";
byte[] utf8Bytes = System.Text.Encoding.UTF8.GetBytes(s_unicode);
Hier ist meine unsichere Implementierung der Konvertierung von String
in Byte[]
:
public static unsafe Byte[] GetBytes(String s)
{
Int32 length = s.Length * sizeof(Char);
Byte[] bytes = new Byte[length];
fixed (Char* pInput = s)
fixed (Byte* pBytes = bytes)
{
Byte* source = (Byte*)pInput;
Byte* destination = pBytes;
if (length >= 16)
{
do
{
*((Int64*)destination) = *((Int64*)source);
*((Int64*)(destination + 8)) = *((Int64*)(source + 8));
source += 16;
destination += 16;
}
while ((length -= 16) >= 16);
}
if (length > 0)
{
if ((length & 8) != 0)
{
*((Int64*)destination) = *((Int64*)source);
source += 8;
destination += 8;
}
if ((length & 4) != 0)
{
*((Int32*)destination) = *((Int32*)source);
source += 4;
destination += 4;
}
if ((length & 2) != 0)
{
*((Int16*)destination) = *((Int16*)source);
source += 2;
destination += 2;
}
if ((length & 1) != 0)
{
++source;
++destination;
destination[0] = source[0];
}
}
}
return bytes;
}
Es ist viel schneller als das eines akzeptierten Anworters, auch wenn es nicht so elegant ist wie es ist. Hier sind meine Stoppuhr-Benchmarks für über 10000000 Iterationen:
[Second String: Length 20]
Buffer.BlockCopy: 746ms
Unsafe: 557ms
[Second String: Length 50]
Buffer.BlockCopy: 861ms
Unsafe: 753ms
[Third String: Length 100]
Buffer.BlockCopy: 1250ms
Unsafe: 1063ms
Um es zu verwenden, müssen Sie in den Build-Eigenschaften Ihres Projekts "Unsicheren Code zulassen" ankreuzen. Ab .NET Framework 3.5 kann diese Methode auch als String-Erweiterung verwendet werden:
public static unsafe class StringExtensions
{
public static Byte[] ToByteArray(this String s)
{
// Method Code
}
}
Wenn Sie wirklich eine Kopie der zugrunde liegenden Bytes einer Zeichenfolge möchten, können Sie eine Funktion wie die folgende verwenden. Das solltest du aber nicht Bitte lies weiter, um herauszufinden warum.
[DllImport(
"msvcrt.dll",
EntryPoint = "memcpy",
CallingConvention = CallingConvention.Cdecl,
SetLastError = false)]
private static extern unsafe void* UnsafeMemoryCopy(
void* destination,
void* source,
uint count);
public static byte[] GetUnderlyingBytes(string source)
{
var length = source.Length * sizeof(char);
var result = new byte[length];
unsafe
{
fixed (char* firstSourceChar = source)
fixed (byte* firstDestination = result)
{
var firstSource = (byte*)firstSourceChar;
UnsafeMemoryCopy(
firstDestination,
firstSource,
(uint)length);
}
}
return result;
}
Mit dieser Funktion erhalten Sie schnell eine Kopie der Bytes, die Ihrer Zeichenfolge zugrunde liegen. Sie erhalten diese Bytes in der Art und Weise, wie sie auf Ihrem System codiert werden. Diese Codierung ist mit ziemlicher Sicherheit UTF-16LE, aber das ist ein Implementierungsdetail, das Sie nicht interessieren sollten.
Es wäre sicherer, einfacher und zuverlässiger einfach anzurufen,
System.Text.Encoding.Unicode.GetBytes()
Höchstwahrscheinlich führt dies zu demselben Ergebnis, ist einfacher zu tippen und die Bytes werden bei einem Aufruf von immer umgeleitet
System.Text.Encoding.Unicode.GetString()
Benutze einfach folgendes:
byte[] myByte= System.Text.ASCIIEncoding.Default.GetBytes(myString);
Die Zeichenfolge kann aufgrund der folgenden Tatsache auf verschiedene Arten in ein Byte-Array konvertiert werden: .NET unterstützt Unicode, und Unicode standardisiert mehrere unterschiedliche Codierungen, die als UTFs bezeichnet werden. Sie haben unterschiedliche Längen der Bytedarstellung, sind jedoch in dem Sinne äquivalent, dass eine codierte Zeichenfolge in die Zeichenfolge zurückcodiert werden kann. Wenn die Zeichenfolge jedoch mit einer UTF codiert und unter der Annahme einer anderen UTF decodiert wird, kann sie verschraubt werden Nach oben.
.NET unterstützt auch Nicht-Unicode-Codierungen, diese sind jedoch im Allgemeinen nicht gültig (gilt nur, wenn eine begrenzte Untermenge von Unicode-Codepunkten in einer tatsächlichen Zeichenfolge, wie z. B. ASCII, verwendet wird). Intern unterstützt .NET UTF-16, aber für die Darstellung von Streams wird in der Regel UTF-8 verwendet. Es ist auch ein De-facto-Standard für das Internet.
Es überrascht nicht, dass die Serialisierung von Zeichenfolgen in ein Byte-Array und die Deserialisierung von der Klasse System.Text.Encoding
unterstützt wird, die eine abstrakte Klasse ist. Die abgeleiteten Klassen unterstützen konkrete Codierungen: ASCIIEncoding
und vier UTFs (System.Text.UnicodeEncoding
unterstützt UTF-16)
Ref dieser Link.
Zur Serialisierung in ein Array von Bytes mit System.Text.Encoding.GetBytes
. Verwenden Sie für die inverse Operation System.Text.Encoding.GetChars
. Diese Funktion gibt ein Array von Zeichen zurück. Um eine Zeichenfolge abzurufen, verwenden Sie einen Zeichenfolgenkonstruktor System.String(char[])
.
Siehe diese Seite.
Beispiel:
string myString = //... some string
System.Text.Encoding encoding = System.Text.Encoding.UTF8; //or some other, but prefer some UTF is Unicode is used
byte[] bytes = encoding.GetBytes(myString);
//next lines are written in response to a follow-up questions:
myString = new string(encoding.GetChars(bytes));
byte[] bytes = encoding.GetBytes(myString);
myString = new string(encoding.GetChars(bytes));
byte[] bytes = encoding.GetBytes(myString);
//how many times shall I repeat it to show there is a round-trip? :-)
Dies liegt daran, dass Tyler so treffend sagte : "Strings sind keine reinen Daten. Sie haben auch Informationen ." In diesem Fall handelt es sich bei den Informationen um eine Codierung, die bei der Erstellung der Zeichenfolge angenommen wurde.
Dies basiert auf dem Kommentar von OP zu seiner eigenen Frage und ist die richtige Frage, wenn ich die Hinweise von OP auf den Anwendungsfall verstehe.
Das Speichern von Binärdaten in Strings ist aufgrund der oben genannten angenommenen Codierung wahrscheinlich der falsche Ansatz! Welches Programm oder welche Bibliothek auch immer diese Binärdaten in einem string
(anstelle eines byte[]
- Arrays, das angemessener gewesen wäre) gespeichert hat, hat den Kampf bereits verloren, bevor er begonnen hat. Wenn sie die Bytes in einer REST Anfrage/Antwort an Sie senden oder irgendetwas, das Zeichenfolgen übertragen muss , Base64 wäre der richtige Ansatz.
Alle anderen haben diese falsche Frage falsch beantwortet.
Wenn die Zeichenfolge so aussieht, wie sie ist, wählen Sie einfach eine Codierung aus (vorzugsweise eine, die mit UTF beginnt), verwenden Sie die entsprechende Funktion System.Text.Encoding.???.GetBytes()
und teilen Sie mit, wem Sie die Bytes geben, für welche Codierung Sie sich entschieden haben.
einfacher Code mit LINQ
string s = "abc"
byte[] b = s.Select(e => (byte)e).ToArray();
BEARBEITEN: wie unten kommentiert, ist es kein guter Weg.
sie können es dennoch verwenden, um LINQ mit einer angemesseneren Codierung zu verstehen:
string s = "abc"
byte[] b = s.Cast<byte>().ToArray();
Zwei Wege:
public static byte[] StrToByteArray(this string s)
{
List<byte> value = new List<byte>();
foreach (char c in s.ToCharArray())
value.Add(c.ToByte());
return value.ToArray();
}
Und,
public static byte[] StrToByteArray(this string s)
{
s = s.Replace(" ", string.Empty);
byte[] buffer = new byte[s.Length / 2];
for (int i = 0; i < s.Length; i += 2)
buffer[i / 2] = (byte)Convert.ToByte(s.Substring(i, 2), 16);
return buffer;
}
Ich neige dazu, die untere öfter zu verwenden als die obere, habe sie nicht auf Geschwindigkeit überprüft.
bytes[] buffer = UnicodeEncoding.UTF8.GetBytes(string something); //for converting to UTF then get its bytes
bytes[] buffer = ASCIIEncoding.ASCII.GetBytes(string something); //for converting to ascii then get its bytes
Ein Zeichen ist sowohl ein Suchschlüssel für eine Schriftartentabelle als auch eine lexikalische Tradition, wie z. B. Reihenfolge, Groß- und Kleinschreibung usw.
Folglich ist ein Zeichen kein Byte (8 Bits) und ein Byte ist kein Zeichen. Insbesondere können die 256 Permutationen eines Bytes nicht die Tausenden von Symbolen in einigen geschriebenen Sprachen aufnehmen, geschweige denn in allen Sprachen. Daher wurden verschiedene Verfahren zum Codieren von Zeichen entwickelt. Einige codieren für eine bestimmte Sprachklasse (ASCII-Codierung). mehrere Sprachen unter Verwendung von Codepages (Extended ASCII); oder ehrgeizig alle Sprachen, indem Sie nach Bedarf zusätzliche Bytes (Unicode) hinzufügen.
In einem System wie .NET Framework impliziert ein String eine bestimmte Zeichenkodierung. In .NET ist diese Codierung Unicode. Da das Framework standardmäßig Unicode liest und schreibt, ist die Zeichencodierung in .NET normalerweise nicht erforderlich.
Um jedoch eine Zeichenfolge aus einem Bytestrom in das System zu laden, müssen Sie die Quellcodierung kennen, um sie zu interpretieren und anschließend korrekt zu übersetzen Kauderwelsch). Wenn eine Zeichenfolge in eine externe Quelle geschrieben wird, wird sie in einer bestimmten Codierung geschrieben.
Von byte[]
bis string
:
return BitConverter.ToString(bytes);
Verwenden Sie die folgende Lösung, um eine Zeichenfolge in ein Byte [] zu konvertieren:
string s = "abcdefghijklmnopqrstuvwxyz";
byte[] b = System.Text.UTF32Encoding.GetBytes(s);
Ich hoffe, es hilft.
Ich habe eine Visual Basic-Erweiterung geschrieben, die der akzeptierten Antwort ähnelt, aber .NET-Speicher und Marshalling direkt für die Konvertierung verwendet, und sie unterstützt Zeichenbereiche, die in anderen Methoden nicht unterstützt werden, z. B. UnicodeEncoding.UTF8.GetString
oder UnicodeEncoding.UTF32.GetString
oder sogar MemoryStream and BinaryFormatter
(ungültige Zeichen wie: ????
& ChrW(55906)
& ChrW(55655)
):
<Extension> _
Public Function ToBytesMarshal(ByRef str As String) As Byte()
Dim gch As GCHandle = GCHandle.Alloc(str, GCHandleType.Pinned)
Dim handle As IntPtr = gch.AddrOfPinnedObject
ToBytesMarshal = New Byte(str.Length * 2 - 1) {}
Try
For i As Integer = 0 To ToBytesMarshal.Length - 1
ToBytesMarshal.SetValue(Marshal.ReadByte(IntPtr.Add(handle, i)), i)
Next
Finally
gch.Free()
End Try
End Function
<Extension> _
Public Function ToStringMarshal(ByRef arr As Byte()) As String
Dim gch As GCHandle = GCHandle.Alloc(arr, GCHandleType.Pinned)
Try
ToStringMarshal = Marshal.PtrToStringAuto(gch.AddrOfPinnedObject)
Finally
gch.Free()
End Try
End Function