Bagaimana cara mengkonversi string
ke byte[]
di .NET (C#) tanpa manual menentukan spesifik encoding?
I'm akan mengenkripsi string. Saya dapat mengenkripsi itu tanpa mengubah, tapi aku'd masih ingin tahu mengapa encoding datang untuk bermain di sini.
Juga, mengapa harus encoding dipertimbangkan? Bisa't saya hanya mendapatkan apa yang byte string yang telah disimpan dalam? Mengapa ada ketergantungan pada pengkodean karakter?
Seperti yang anda sebutkan, tujuan anda adalah untuk hanya "mendapatkan apa yang byte string yang telah disimpan dalam". (Dan, tentu saja, untuk dapat membangun kembali string dari byte.)
Hanya melakukan ini sebagai gantinya:
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);
}
Selama program anda (atau program lain) don't mencoba untuk menafsirkan byte entah bagaimana, yang jelas tidak't menyebutkan anda berniat untuk melakukannya, maka tidak tidak ada yang salah dengan pendekatan ini! Khawatir tentang pengkodean hanya membuat hidup anda lebih rumit karena tidak ada alasan yang nyata.
Itu akan dikodekan dan diterjemahkan sama saja, karena anda hanya melihat byte.
Jika anda menggunakan pengkodean tertentu, meskipun, itu akan've memberikan anda masalah dengan encoding/decoding karakter yang tidak valid.
Hal ini tergantung pada encoding string (ASCII, UTF-8, ...).
Misalnya:
byte[] b1 = System.Text.Encoding.UTF8.GetBytes (myString);
byte[] b2 = System.Text.Encoding.ASCII.GetBytes (myString);
Contoh kecil mengapa encoding hal-hal:
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 hanya isn't dilengkapi untuk menangani karakter khusus.
Secara internal,.NET framework menggunakan UTF-16 untuk mewakili string, jadi jika anda hanya ingin mendapatkan yang tepat byte yang .NET menggunakan, gunakan Sistem.Teks.Encoding.Unicode.GetBytes (...)
.
Melihat Encoding Karakter di .NET Framework (MSDN) untuk informasi lebih lanjut.
Jawaban yang diterima adalah sangat, sangat rumit. Gunakan disertakan .NET kelas ini:
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 menemukan kembali roda jika anda don't harus...
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());
Anda perlu untuk mengambil encoding ke account, karena 1 karakter dapat diwakili oleh 1 atau lebih byte (sampai sekitar 6), dan pengkodean yang berbeda akan memperlakukan byte ini berbeda.
Joel telah posting ini:
Ini adalah sebuah pertanyaan yang populer. Hal ini penting untuk memahami apa yang dimaksud penulis adalah bertanya, dan bahwa itu adalah berbeda dari apa yang mungkin yang paling umum perlu. Untuk mencegah penyalahgunaan kode di mana hal ini tidak diperlukan, saya've menjawab nanti dulu.
Setiap string memiliki set karakter dan encoding. Ketika anda mengkonversi sebuah Sistem.String
objek untuk sebuah array dari Sistem.Byte
anda masih memiliki set karakter dan encoding. Untuk sebagian besar, penggunaan, anda'd tahu yang set karakter dan encoding yang anda butuhkan dan .BERSIH membuatnya sederhana untuk "copy dengan konversi." Hanya memilih yang tepat Encoding
kelas.
// using System.Text;
Encoding.UTF8.GetBytes(".NET String to byte array")
Konversi mungkin perlu untuk menangani kasus-kasus di mana karakter target yang ditetapkan atau encoding doesn't dukungan karakter yang's di sumber. Anda memiliki beberapa pilihan: pengecualian, substitusi atau melompat-lompat. Kebijakan default adalah untuk menggantikan '?'.
// using System.Text;
var text = Encoding.ASCII.GetString(Encoding.ASCII.GetBytes("You win €100"));
// -> "You win ?100"
Jelas, konversi tidak selalu lossless!
Catatan: Untuk Sistem.String
sumber set karakter Unicode.
Satu-satunya hal yang membingungkan adalah bahwa .NET menggunakan nama dari karakter set untuk nama salah satu encoding karakter yang ditetapkan. Encoding.Unicode
harus disebut Encoding.UTF16
.
That's ini untuk sebagian besar penggunaan. Jika itu's apa yang anda butuhkan, berhenti membaca di sini. Melihat menyenangkan Joel Spolsky artikel jika anda don't memahami apa pengkodean.
Sekarang, pertanyaan penulis bertanya, "Setiap string disimpan sebagai array byte, kan? Mengapa bisa't saya hanya memiliki orang-orang byte?"
Dia doesn't ingin ada konversi.
Dari C# spec:
Karakter dan pengolahan string dalam C# menggunakan Unicode encoding. Char jenis merupakan sebuah unit kode UTF-16, dan tipe string merupakan urutan kode UTF-16 unit.
Jadi, kita tahu bahwa jika kita meminta null konversi (yaitu, dari UTF-16 ke UTF-16), we'll mendapatkan hasil yang diinginkan:
Encoding.Unicode.GetBytes(".NET String to byte array")
Tapi untuk menghindari penyebutan pengkodean, kita harus melakukannya dengan cara lain. Jika perantara tipe data yang diterima, ada konseptual pintas untuk ini:
".NET String to byte array".ToCharArray()
Itu doesn't mendapatkan yang diinginkan datatype tapi Mehrdad's jawaban menunjukkan bagaimana untuk mengubah ini Char array Byte array menggunakan BlockCopy. Namun, ini salinan string dua kali! Dan, itu juga secara eksplisit menggunakan encoding-kode tertentu: datatype Sistem.Char
.
Satu-satunya cara untuk mendapatkan yang sebenarnya byte String disimpan dalam adalah dengan menggunakan pointer. Yang tetap
pernyataan memungkinkan mengambil alamat dari nilai-nilai. Dari C# spec:
[Untuk] sebuah ekspresi dari tipe string, ... yang penginisialisasi menghitung alamat dari karakter pertama dalam string.
Untuk melakukannya, compiler menulis kode melewatkan bagian-bagian lain dari objek string dengan RuntimeHelpers.OffsetToStringData
. Jadi, untuk mendapatkan bahan baku bytes, hanya membuat pointer ke string dan copy jumlah byte yang diperlukan.
// 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;
}
Seperti @CodesInChaos mencontohkan, hasilnya tergantung pada endianness mesin. Tapi pertanyaan penulis tidak peduli dengan itu.
Bagian pertama dari pertanyaan anda (bagaimana untuk mendapatkan byte) sudah dijawab oleh orang lain: terlihat di Sistem.Teks.Encoding` namespace.
Saya akan membahas tindak pertanyaan: mengapa anda perlu memilih encoding? Mengapa bisa't anda mendapatkan bahwa dari class string itu sendiri?
Jawabannya adalah dalam dua bagian.
Pertama-tama, byte digunakan secara internal oleh class string don't matter, dan setiap kali anda menganggap mereka lakukan anda're kemungkinan memperkenalkan bug.
Jika program anda adalah sepenuhnya dalam .Net world maka anda don't perlu khawatir tentang mendapatkan byte array untuk string sama sekali, bahkan jika anda're mengirimkan data melalui jaringan. Sebaliknya, gunakan .Net Serialisasi untuk khawatir tentang transmisi data. Anda don't khawatir tentang yang sebenarnya byte lagi: Serialisasi formatter melakukannya untuk anda.
Di sisi lain, bagaimana jika anda mengirim byte ini di suatu tempat yang dapat anda't menjamin akan menarik data dari .Net serial stream? Dalam hal ini anda tidak perlu khawatir tentang pengkodean, karena jelas ini sistem eksternal yang peduli. Jadi sekali lagi, internal byte yang digunakan oleh string don't peduli: anda perlu untuk memilih encoding sehingga anda dapat eksplisit tentang hal ini pengkodean pada akhir penerimaan, bahkan jika itu's pengkodean yang sama digunakan secara internal oleh .Net.
Saya mengerti bahwa dalam hal ini anda mungkin lebih memilih untuk menggunakan yang sebenarnya byte disimpan oleh variabel string dalam memori di mana mungkin, dengan gagasan bahwa hal itu mungkin menyimpan beberapa pekerjaan yang membuat anda byte stream. Namun, aku meletakkannya untuk anda's tidak hanya penting dibandingkan untuk membuat yakin bahwa anda output dipahami di ujung yang lain, dan untuk menjamin bahwa anda must secara eksplisit dengan encoding. Selain itu, jika anda benar-benar ingin untuk mencocokkan internal byte, anda sudah bisa hanya memilih Unicode
encoding, dan mendapatkan bahwa kinerja tabungan.
Yang membawa saya ke bagian kedua... memilih Unicode
encoding adalah menceritakan .Net menggunakan mendasari byte. Anda tidak perlu memilih encoding ini, karena ketika beberapa model baru Unicode-Plus keluar .Net runtime harus bebas untuk menggunakan cara yang lebih baru, lebih baik encoding model tanpa melanggar program anda. Tapi, untuk saat ini (dan masa mendatang), hanya memilih pengkodean Unicode memberikan apa yang anda inginkan.
It's juga penting untuk memahami string anda memiliki untuk menjadi re-tertulis untuk kawat, dan melibatkan setidaknya beberapa terjemahan dari bit-pola even ketika anda menggunakan pencocokan encoding. Komputer perlu memperhitungkan hal-hal seperti Besar vs Little Endian, network byte order, pembentukan paket, informasi sesi, dll.
Hanya untuk menunjukkan bahwa Mehrdrad's suara jawaban karya, pendekatan ini bahkan dapat bertahan berpasangan pengganti karakter(yang banyak dilontarkan terhadap jawaban saya, tapi yang semua orang sama-sama bersalah, misal Sistem.Teks.Encoding.UTF8.GetBytes
, Sistem.Teks.Encoding.Unicode.GetBytes
; orang-encoding metode yang dapat't bertahan tinggi pengganti karakter d800
misalnya, dan orang-orang yang hanya sekedar menggantikan tinggi pengganti karakter dengan nilai 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);
}
}
Output:
T 54
e 65
s 73
t 74
? d800
T 54
e 65
s 73
t 74
Coba dengan Sistem.Teks.Encoding.UTF8.GetBytes atau Sistem.Teks.Encoding.Unicode.GetBytes, mereka hanya akan mengganti tinggi pengganti karakter dengan nilai fffd
Setiap kali ada's sebuah gerakan dalam pertanyaan ini, saya'm masih memikirkan serializer(baik itu dari Microsoft atau dari pihak ke-3 komponen) yang dapat bertahan string yang mengandung berpasangan pengganti karakter; aku google ini setiap sekarang dan kemudian: serialisasi berpasangan pengganti karakter .NET. Ini doesn't membuat saya kehilangan tidur, tapi itu's agak menjengkelkan ketika setiap sekarang dan kemudian ada's seseorang mengomentari jawaban saya bahwa itu's cacat, namun jawaban mereka sama-sama cacat ketika datang untuk berpasangan pengganti karakter.
Darn, Microsoft seharusnya hanya digunakan Sistem.Buffer.BlockCopy
dalam BinaryFormatter
ツ
谢谢!
Yah, aku'telah membaca semua jawaban dan mereka akan menggunakan pengkodean atau men-serialisasi yang turun berpasangan pengganti.
It's buruk ketika string, misalnya, berasal dari SQL Server di mana ia dibangun dari byte array menyimpan, misalnya, password hash. Jika kita menjatuhkan sesuatu dari hal itu,'ll menyimpan hash tidak valid, dan jika kita ingin menyimpannya dalam XML, kita ingin meninggalkan utuh (karena XML penulis tetes pengecualian pada setiap berpasangan pengganti yang ditemukan).
Jadi saya gunakan Base64 encoding dari byte array dalam kasus tersebut, tapi, hei, di Internet hanya ada satu solusi untuk hal ini di dalam C#, dan memiliki bug di dalamnya dan hanya salah satu cara, jadi saya've tetap bug dan ditulis kembali prosedur. Di sini anda, masa depan karyawan 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);
}
Juga tolong jelaskan mengapa pengkodean harus diambil ke dalam pertimbangan. Dapat't saya hanya mendapatkan apa yang byte string yang telah disimpan dalam? Mengapa ini ketergantungan pada encoding?!!!
Karena tidak ada hal seperti itu sebagai "byte dari string".
String (atau lebih umum, teks) yang terdiri dari karakter: huruf, angka, dan simbol-simbol lainnya. Yang's semua. Komputer, namun, tidak tahu apa-apa tentang karakter; mereka hanya dapat menangani byte. Oleh karena itu, jika anda ingin menyimpan atau mengirimkan teks dengan menggunakan komputer, anda perlu untuk mengubah karakter dengan byte. Bagaimana anda melakukan itu? Berikut ini's dimana pengkodean yang datang ke tempat kejadian.
Encoding adalah apa-apa tapi konvensi untuk menerjemahkan logis karakter fisik byte. Yang paling sederhana dan paling dikenal pengkodean ASCII, dan itu adalah semua yang anda butuhkan jika anda menulis dalam bahasa inggris. Untuk bahasa lain anda akan membutuhkan lebih lengkap pengkodean, menjadi salah satu Unicode rasa pilihan yang paling aman saat ini.
Jadi, dalam jangka pendek, mencoba untuk "mendapatkan byte dari string tanpa menggunakan pengkodean" ini mungkin sebagai "menulis teks tanpa menggunakan bahasa".
By the way, saya sangat menyarankan anda (dan siapapun) untuk membaca ini bagian kecil dari kebijaksanaan: Minimum Absolut Setiap Pengembang perangkat Lunak benar-Benar, Positif Harus Tahu Tentang Unicode dan Set Karakter (Tidak ada Alasan!)
Anda dapat menggunakan kode berikut untuk konversi antara string dan array byte.
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);
Dengan munculnya Span<T>
dirilis dengan C# 7.2, kanonik teknik untuk menangkap mendasari memori representasi dari sebuah string menjadi berhasil byte array adalah:
byte[] bytes = "rubbish_\u9999_string".AsSpan().AsBytes().ToArray();
Mengubahnya kembali harus non-starter karena itu berarti anda sebenarnya menafsirkan data entah bagaimana, tapi demi kelengkapan:
string s;
unsafe
{
fixed (char* f = &bytes.AsSpan().NonPortableCast<byte, char>().DangerousGetPinnableReference())
{
s = new string(f);
}
}
Nama-nama NonPortableCast
dan DangerousGetPinnableReference
harus lebih argumen bahwa seharusnya kau't melakukan hal ini.
Perhatikan bahwa bekerja dengan Span<T>
membutuhkan menginstal Sistem.Memori NuGet package.
Terlepas dari, aktual pertanyaan asli dan follow-up comments menyiratkan bahwa yang mendasari memori tidak menjadi "diinterpretasikan" (yang saya asumsikan berarti tidak dimodifikasi atau membaca di luar kebutuhan untuk menulis sebagai-adalah), menunjukkan bahwa beberapa implementasi dari Aliran
kelas harus digunakan sebagai pengganti dari penalaran tentang data-data sebagai string di semua.
I'm tidak yakin, tapi saya pikir string toko info nya sebagai array dari Karakter, yang tidak efisien dengan byte. Secara khusus, definisi dari Char "Mewakili karakter Unicode".
ambil contoh ini contoh:
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));
}
Perhatikan bahwa Unicode jawabannya adalah 14 byte dalam kedua kasus, sedangkan UTF-8 jawabannya adalah hanya 9 byte pertama, dan hanya 7 untuk yang kedua.
Jadi, jika anda hanya ingin byte yang digunakan oleh string, hanya menggunakan Encoding.Unicode
, tapi itu akan menjadi tidak efisien dengan ruang penyimpanan.
Masalah utama adalah bahwa mesin terbang dalam sebuah string membutuhkan 32 bit (16 bit untuk kode karakter) tapi byte hanya memiliki 8 bit untuk cadangan. Satu-ke-satu pemetaan doesn't ada kecuali jika anda membatasi diri anda untuk string yang hanya berisi karakter ASCII. Sistem.Teks.Pengkodean ini memiliki banyak cara untuk memetakan string byte[], anda perlu memilih salah satu yang menghindari hilangnya informasi dan yang mudah untuk digunakan oleh klien anda ketika dia membutuhkan untuk peta byte[] kembali ke string.
Utf8 adalah tempat encoding, hal ini kompak dan tidak lossy.
Bagaimana cara mengkonversi string ke byte[] di .NET (C#) tanpa manual menentukan spesifik encoding?
A [string][1] di .NET merupakan teks sebagai urutan kode UTF-16 unit, sehingga byte yang dikodekan dalam memori dalam UTF-16 sudah.
Mehrdad's Jawaban
Anda dapat menggunakan Mehrdad's jawaban, tapi itu tidak benar-benar menggunakan pengkodean karena karakter UTF-16. Itu panggilan ToCharArray yang melihat sumber menciptakan char[]
dan salinan memori secara langsung. Maka salinan data ke byte array yang dialokasikan. Jadi di bawah tenda itu adalah menyalin mendasari byte dua kali dan mengalokasikan array char yang tidak digunakan setelah panggilan.
Tom Blodget's Jawaban
Tom Blodget's jawaban adalah 20-30% lebih cepat dari Mehrdad sejak itu melompat langkah menengah mengalokasikan array char dan menyalin byte untuk itu, tetapi membutuhkan anda mengkompilasi dengan /tidak aman
pilihan. Jika anda benar-benar tidak ingin menggunakan encoding, saya pikir ini adalah cara untuk pergi. Jika anda menempatkan anda enkripsi login di dalam tetap
blok, anda don't bahkan perlu mengalokasikan terpisah byte array dan copy byte untuk itu.
Juga, mengapa harus encoding dipertimbangkan? Bisa't saya hanya mendapatkan apa yang byte string yang telah disimpan dalam? Mengapa ada ketergantungan pada pengkodean karakter?
Karena itu adalah cara yang tepat untuk melakukannya. string
adalah sebuah abstraksi.
Menggunakan pengkodean yang bisa memberikan anda masalah jika anda memiliki 'strings' dengan karakter yang tidak valid, tapi itu tidak't terjadi. Jika anda mendapatkan data menjadi string dengan karakter yang tidak valid yang anda lakukan itu salah. Anda mungkin harus menggunakan byte array atau Base64 encoding untuk memulai dengan.
Jika anda menggunakan Sistem.Teks.Encoding.Unicode
, kode anda akan menjadi lebih tangguh. Anda don't perlu khawatir tentang endianness sistem kode anda akan berjalan pada. Anda don't perlu khawatir jika versi berikutnya dari CLR akan menggunakan internal yang berbeda karakter encoding.
Saya pikir pertanyaan isn't mengapa anda ingin khawatir tentang encoding, tetapi mengapa anda ingin mengabaikannya dan menggunakan sesuatu yang lain. Pengkodean dimaksudkan untuk mewakili abstraksi dari sebuah string di urutan byte. Sistem.Teks.Encoding.Unicode
akan memberikan anda sedikit endian urutan byte encoding dan akan melakukan hal yang sama pada setiap sistem, sekarang dan di masa depan.
[1]: https://msdn.microsoft.com/en-us/library/system.string(v=vs. 110).aspx