Cum pot converti un "string" a o byte[]
în .NET (C#), fără manual specificând un anumit codare?
Am'm de gând să cripta șir. Eu pot cripta fără conversie, dar am'd încă mai vrea să știu de ce codare vine să joace aici.
De asemenea, de ce ar trebui să codare fi luate în considerare? Poate't I pur și simplu de a obține ceea ce bytes șir a fost stocate în? De ce există o dependență pe caracterelor?
Cum ați menționat, scopul tău este, pur și simplu, să "ce bytes șir a fost stocate în". (Și, desigur, să fie capabil de a re-construi șirul de octeți.)
Face acest lucru in schimb:
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);
}
Atâta timp cât programul (sau alte programe) don't încerca să interpretarea octeți într-un fel, pe care, evident, nu't mai vorbim ai de gând să faci, atunci nu există nimic în neregulă cu această abordare! Îngrijorătoare despre codificări doar face viața mai complicată pentru nici un motiv real.
Acesta va fi codificat și decodificat la fel, pentru că sunt doar uitându-te la bytes.
Dacă ai folosit o codificare specifice, deși, s-ar'am dat probleme cu codare/decodare caractere nevalide.
Depinde de codificarea șirul (ASCII, UTF-8, ...).
De exemplu:
byte[] b1 = System.Text.Encoding.UTF8.GetBytes (myString);
byte[] b2 = System.Text.Encoding.ASCII.GetBytes (myString);
O mică mostră de ce codare aspecte:
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 pur și simplu nu - 't echipate să se ocupe cu caractere speciale.
Pe plan intern,.NET framework foloseste UTF-16 pentru a reprezenta siruri de caractere, deci, dacă doriți pur și simplu pentru a obține exact bytes asta .NET foloseste, utilizarea Sistemului.Text.Codare.Unicode.GetBytes (...)`.
Vezi Codificarea caracterelor în .NET Framework (MSDN) pentru mai multe informații.
Acceptat răspunsul este foarte, foarte complicat. Utilizați incluse .NET clase pentru acest lucru:
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);
Don't reinventeze roata, dacă nu't trebuie să...
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());
Aveți nevoie pentru a lua codare în considerare, pentru că 1 personaj ar putea fi reprezentat de 1 sau mai mult bytes (până la aproximativ 6), și diferite codificări va trata aceste bytes diferit.
Joel are o postare pe asta:
Aceasta este o întrebare populară. Este important să înțelegem ce întrebare autorul se întreabă, și că este diferit de ceea ce este probabil cel mai comun nevoie. Pentru a descuraja abuzul de cod în cazul în care nu este nevoie, am'am răspuns mai târziu primul.
Fiecare șir are un set de caractere și codificarea. Atunci când convertiți un Sistem.Stringobiect la o serie de
Sistem.Byte` mai ai un set de caractere și codificarea. Pentru cele mai multe utilizări, ai'd știu ce set de caractere și codificarea ai nevoie și .NET face simplu pentru a "copia cu conversie." Doar alege adecvat de Codificare clasa.
// using System.Text;
Encoding.UTF8.GetBytes(".NET String to byte array")
Conversia poate nevoie să se ocupe de cazurile în care ținta set de caractere sau de codare nu't suport un personaj care's în sursă. Aveți câteva opțiuni: excepție, substituire sau sărind peste. Politica implicită este de a substitui o '?'.
// using System.Text;
var text = Encoding.ASCII.GetString(Encoding.ASCII.GetBytes("You win €100"));
// -> "You win ?100"
Evident conversiile nu sunt neapărat pierderi!
Notă: Pentru Sistem.String` sursa set de caractere Unicode.
Singurul lucru confuz este că .NET foloseste numele unui set de caractere pentru numele de o anumită codare de care set de caractere. Codare.Unicode
ar trebui să fie numit de Codare.UTF16
.
That's pentru cele mai multe utilizări. Dacă asta's de ce ai nevoie, opri din citit aici. Vezi distractiv Joel Spolsky articolul dacă nu't înțeleagă ceea ce o codificare este.
Acum, întrebarea pe care autorul cere, "Fiecare șir este stocat ca un array de bytes, nu? De ce't pur și simplu, cei bytes?"
El nu't vreau nici o conversie.
De C# spec:
Caracter și șir de prelucrare în C# folosește codificarea Unicode. Char tip reprezintă o UTF-16 cod unitate, și de tip string reprezintă un secvența de UTF-16 unități de cod.
Deci, noi știm că, dacă cerem pentru nul de conversie (de exemplu, de la UTF-16, UTF-16), ne-am'll a obține rezultatul dorit:
Encoding.Unicode.GetBytes(".NET String to byte array")
Dar, pentru a evita menționarea codificări, trebuie să facem în alt fel. În cazul în care un intermediar de tip de date este acceptabilă, există o conceptuale scurtătură pentru acest lucru:
".NET String to byte array".ToCharArray()
Asta nu't ne dorite de date, dar Mehrdad's a răspunde arată cum de a converti această matrice Char la o matrice Octet folosind BlockCopy. Cu toate acestea, aceasta copiază șirul de două ori! Și, se prea folosește explicit de codare specifice cod: tipul de date a Sistemului.Char`.
Singura modalitate de a ajunge la real bytes Șirul este stocat în este de a utiliza un pointer. La " fix " declarație permite luarea adresa de valori. Din C# spec.:
[Pentru] o expresie de tip șir de caractere, ... de inițializare calculează adresa primului caracter din șir.
Pentru a face acest lucru, compilatorul scrie cod sări peste alte piese de obiect string cu RuntimeHelpers.OffsetToStringData`. Deci, pentru a obține prime bytes, doar a crea un pointer la șir de caractere și copia numărul de octeți necesar.
// 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;
}
Ca @CodesInChaos subliniat, rezultatul depinde de endianness a mașinii. Dar întrebarea autorul nu este preocupat de asta.
Prima parte a întrebării dumneavoastră (cum să obțineți bytes) a fost deja preluat de către alții: uită-te în Sistem.Text.Codificarea` de nume.
Vă voi răspunde la întrebare: de ce aveți nevoie pentru a alege o codare? De ce't ai înțeles asta din clasa string sine?
Răspunsul este în două părți.
Mai întâi de toate, octeți folosit intern de către clasa string nu't matter_, și ori de câte ori presupunem că ai're ar putea introduce un bug.
Dacă programul este în întregime în .Net lumii, atunci nu't nevoie să vă faceți griji cu privire la obtinerea octet matrice de siruri de caractere de la toate, chiar daca're trimiterea de date printr-o rețea. În schimb, utilizați .Net Serialization să vă faceți griji despre a transmite datele. Nu't vă faceți griji despre bytes nici mai mult: Serialization formatter face pentru tine.
Pe de altă parte, dacă sunteți trimiterea acestor bytes undeva că se poate't de garantare va trage în datele dintr-un .Net serializat? În acest caz, cu siguranta ai nevoie pentru a vă faceți griji despre codare, pentru că, evident, acest sistem extern îi pasă. Deci, din nou, interne bytes utilizate de către string don't contează: aveți nevoie pentru a alege o codificare astfel încât să puteți fi explicit despre această codificare pe la sfârșitul primirea, chiar dacă-l's la fel de codare folosit intern de către .Net.
Am înțeles că în acest caz s-ar putea prefera să utilizeze efectiv de octeți stocate de variabilă șir în memorie în cazul în care este posibil, cu ideea că s-ar putea salva ceva de lucru crearea de flux de octeți. Cu toate acestea, am pus-o să te l's deloc important comparativ cu asigurându-vă că dvs. de ieșire este de înțeles, la celălalt capăt, și pentru a garanta că veți must fi explicite cu codare. În plus, dacă chiar vrei pentru a se potrivi dvs. de interne bytes, deja puteți alege doar Unicode
codare, și obține performanță de economii.
Ceea ce mă aduce la cea de-a doua parte... alege Unicode
de codificare este spune .Net pentru a folosi fond al sistemului bytes. Aveți nevoie pentru a alege această codificare, pentru că atunci când un nou-ultramoderne Unicode-Plus iese .Net runtime trebuie să fie liber pentru a utiliza această nouă, mai bună codificare model fără să-ți rupi program. Dar, pentru moment (și viitor previzibil), doar alegerea de codificare Unicode vă oferă ceea ce vrei.
L's, de asemenea, important să se înțeleagă șirul trebuie să fie re-scris pentru sârmă, și care implică cel puțin o traducere a bit-model even atunci când utilizați o potrivire encoding. Calculatorul are nevoie de a ține cont de astfel de lucruri Mari vs Little Endian, network byte order, packetization, sesiuni de informare, etc.
Doar pentru a demonstra că Mehrdrad's de sunet răspunde lucrări, abordarea lui poate chiar persista nepereche surogat de caractere(dintre care mulți au nivelat împotriva răspunsul meu, dar de care toți sunt la fel de vinovați, de exemplu, Sistemul.Text.Codare.UTF8.GetBytes
, Sistem.Text.Codare.Unicode.GetBytes
; aceste metode de codificare poate't persistă mare surogat personajelor d800de exemplu, și cei care doar pur și simplu înlocuiți de înaltă surogat de caractere cu valoarea
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);
}
}
Ieșire:
T 54
e 65
s 73
t 74
? d800
T 54
e 65
s 73
t 74
Incercati asta cu de Sistem.Text.Codare.UTF8.GetBytes sau de Sistem.Text.Codare.Unicode.GetBytes, doar vor înlocui înaltă surogat personaje cu valoare fffd
De fiecare dată acolo's o mișcare în această întrebare, am'm tot gândesc de o serializer(fie ea de la Microsoft sau de la a 3-a parte componentă) care poate persista siruri de caractere, chiar și conține nepereche surogat de caractere; I google asta în fiecare acum și apoi: serialization nepereche surogat caracter .NET. Asta nu't mă face să-mi pierd somnul, dar's un fel de enervant atunci când fiecare acum și apoi, nu's cineva comentând răspunsul meu că-l's defecte, dar răspunsurile lor sunt la fel de eronate atunci când vine vorba de a nepereche surogat de caractere.
Darn, Microsoft ar fi folosit Sistemul.Tampon.BlockCopyîn
BinaryFormatter` ツ
谢谢!
Ei bine, am'am citit toate raspunsurile si au fost despre utilizarea codare sau unul despre serialization care scade nepereche surogate.
L's rele atunci când șirul, de exemplu, vine de la SQL Server în cazul în care acesta a fost construit de un octet matrice de stocare, de exemplu, o parola hash. Dacă renunțăm la nimic din el, l'll magazin un invalid hash, și dacă vrem să-l stocați în XML, vrem să-l lase intact (deoarece XML scriitor picături o excepție de la orice nepereche surogat se găsește).
Asa ca am folosi Base64 codare de octet matrice, în astfel de cazuri, dar hei, pe Internet există o singură soluție pentru acest lucru în C#, și are bug-uri în ea și este o singură cale, așa că am'am reparat bug-ul și-a scris din nou procedura. Aici sunt, viitorul google:
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);
}
de Asemenea, vă rugăm să explicați de ce codare ar trebui să fie luate în considerare. Pot't I pur și simplu de a obține ceea ce bytes șir a fost stocate în? de Ce acest dependența de codare?!!!
Pentru că nu există nici un astfel de lucru ca "octeți din șirul".
Un șir de caractere (sau mai generic, un text) este compus din caractere: litere, cifre și alte simboluri. Ca's toate. Calculatoare, cu toate acestea, nu știu nimic despre personaje; ele pot ocupa doar bytes. Prin urmare, dacă doriți pentru a stoca sau transmite textul cu ajutorul unui computer, aveți nevoie pentru a transforma personajele să bytes. Cum faci asta? Aici's unde codificări ajuns la locul faptei.
O codificare nu este altceva decât o convenție pentru a traduce logic caractere fizice bytes. Cel mai simplu și cel mai cunoscut codare este ASCII, și este tot ce ai nevoie dacă ai scrie în limba engleză. Pentru alte limbi, veți avea nevoie de mai completă codificări, fiind oricare dintre Unicode arome cea mai sigură alegere în zilele noastre.
Deci, pe scurt, încercarea de a "ia bytes dintr-un șir fără a utiliza codificări" este la fel de imposibil ca "scris un text fără a utiliza orice limbă".
Apropo, am recomandăm să vă (și oricine, pentru care contează) pentru a citi această mică bucată de înțelepciune: Minim Absolut Fiecare Dezvoltator de Software Absolut, Pozitiv Trebuie să Știți Despre Unicode și Seturi de Caractere (Fără Scuze!)
Puteți folosi următorul cod pentru conversia între coarde și matrice octet.
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);
Odată cu apariția de Span<T>
, lansat cu C# 7.2, canonic tehnica de a capta fond al sistemului de memorie reprezentare a unui șir într-un reușit octet matrice este:
byte[] bytes = "rubbish_\u9999_string".AsSpan().AsBytes().ToArray();
Conversia înapoi ar trebui să fie un non-starter pentru că asta înseamnă că sunt, de fapt, interpretarea datelor într-un fel, dar pentru motive de exhaustivitate:
string s;
unsafe
{
fixed (char* f = &bytes.AsSpan().NonPortableCast<byte, char>().DangerousGetPinnableReference())
{
s = new string(f);
}
}
Numele NonPortableCast " și " DangerousGetPinnableReference
ar trebui, de asemenea argumentul că nu ar trebui't face acest lucru.
Rețineți că lucrează cu Span
Indiferent, real original întrebare și follow-up comentarii implică faptul că de fond al sistemului de memorie nu este "interpretat" (care presupun că înseamnă că nu este modificat sau de a citi dincolo de nevoia de a scrie așa cum e), indicând faptul că unele punerea în aplicare a "Stream" de clasă ar trebui să fie folosit în loc de raționament despre date ca șiruri, la toate.
Am'm nu sunt sigur, dar cred șir de magazine de informații ca o matrice de Caractere, care este ineficient cu bytes. În special, definiția unui Char este "Reprezintă un caracter Unicode".
ia acest exemplu de probă:
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));
}
Ia act de faptul că Unicode răspunsul este de 14 octeți în ambele cazuri, întrucât UTF-8 răspuns este de doar 9 bytes pentru prima, și numai 7 pentru cel de-al doilea.
Deci, dacă doriți doar octeți folosit de șir, pur și simplu folosesc Codare.Unicode`, dar va fi ineficientă cu spatiu de depozitare.
Problema cheie este că un simbol într-un șir are 32 de biți (16 biți pentru un cod de caracter), ci un octet are numai 8 biți de rezervă. O unu-la-unu de cartografiere nu't există dacă te limitezi la siruri de caractere care conțin numai caractere ASCII. Sistem.Text.Codificarea are o mulțime de moduri de a mapa un șir de octeți[], aveți nevoie pentru a alege unul care să evite pierderea de informații și care este ușor de utilizat de către client, atunci când ea are nevoie pentru a harta byte[] înapoi la un șir de caractere.
Utf8 este un punct de codare, este compact și nu pierderi.
Cum pot converti un string la un byte[] în .NET (C#), fără manual specificând un anumit codare?
O [string][1].NET reprezintă textul ca o secvență de UTF-16 unități de cod, astfel încât bytes sunt codificate în memorie în UTF-16 deja.
Mehrdad's Răspuns
Puteți utiliza Mehrdad's a răspunde, dar se folosesc de fapt o codificare pentru caractere sunt UTF-16. Se solicită ToCharArray care se uită la sursa creează un char [] și copii de memorie pentru a-l direct. Apoi se copiază datele pe un octet matrice care este, de asemenea, alocat. Deci, sub capota este copierea de fond al sistemului bytes de două ori ** și alocarea unei matrice char care nu este utilizat după apel.
Tom Blodget's Răspuns
Tom Blodget's a răspunde este de 20-30% mai rapid decât Mehrdad deoarece se sare peste etape intermediare de alocare a o matrice char și copierea octeți pentru ea, dar este nevoie de compilați cu /nesigur
opțiune. Dacă absolut nu doriți să utilizați codificarea, cred că aceasta este calea de a merge. Dacă ți-ai pus criptare autentificare în interiorul "fixe" de bloc, nu't chiar trebuie să aloce separat matrice octet și copia octeți pentru ea.
de Asemenea, de ce ar trebui să codare fi luate în considerare? Poate't I pur și simplu de a obține ceea ce bytes șir a fost stocate în? De ce există o dependență pe caracterelor?
Pentru că este modul corect de a face asta. "string" este o abstracție.
Folosind o codificare ar putea da probleme dacă aveți 'siruri de caractere' cu caractere nevalide, dar care ar trebui't se întâmple. Dacă sunteți obtinerea de date în șir cu caractere nevalide că faci ceva greșit. Probabil că ar trebui să fie folosind un octet matrice sau o codare Base64 pentru a începe cu.
Dacă utilizați Sistemul.Text.Codare.Unicode`, codul va fi mai rezistent. Nu't trebuie să vă faceți griji despre endianness din sistemul dvs. va fi codul care rulează pe. Nu't nevoie să vă faceți griji dacă următoarea versiune a CLR va folosi un alt interne de codare a caracterelor.
Cred că întrebarea e't de ce vreți să vă faceți griji despre codare, dar de ce vrei să-l ignore și de a folosi altceva. Codificarea reprezintă abstractizarea unui șir într-o secvență de octeți. Sistemul.Text.Codare.Unicode
va da o little endian byte pentru codare și de a efectua același în fiecare sistem, acum și în viitor.
[1]: https://msdn.microsoft.com/en-us/library/system.string(v=vs. 110).aspx