Mengubah string ke byte array di C #

670

Saya mengubah sesuatu dari VB menjadi C #. Mengalami masalah dengan sintaks dari pernyataan ini:

if ((searchResult.Properties["user"].Count > 0))
{
    profile.User = System.Text.Encoding.UTF8.GetString(searchResult.Properties["user"][0]);
}

Saya kemudian melihat kesalahan berikut:

Argumen 1: tidak dapat mengonversi dari 'objek' ke 'byte []'

Metode overload terbaik untuk 'System.Text.Encoding.GetString (byte [])' memiliki beberapa argumen yang tidak valid

Saya mencoba memperbaiki kode berdasarkan posting ini , tetapi masih belum berhasil

string User = Encoding.UTF8.GetString("user", 0);

Ada saran?

waktu
sumber
1
Apa jenis searchResult.Properties["user"][0]? Coba casting byte[]terlebih dahulu
mshsayem
mshsayem pergi ke mana aku pergi. Apakah Anda melewatkan pemeran untuk (byte[])di hasil pencarian?
Harrison
2
Anda perlu mencari tahu apa jenisnya Properties["user"][0]. Jika Anda yakin ini adalah array byte maka Anda dapat melakukan seperti iniprofile.User = System.Text.Encoding.UTF8.GetString((byte[])searchResult.Properties["user"][0]);
keyboardP
1
Ternyata tidak perlu untuk semua keributan itu. Bagaimanapun, nama pengguna bisa diambil tanpa pengkodean.
nouptime
3
Mengapa Anda tidak memilih jawaban yang benar?
Ali

Jawaban:

1189

Jika Anda sudah memiliki array byte maka Anda harus tahu jenis pengkodean apa yang digunakan untuk membuatnya menjadi array byte.

Misalnya, jika array byte dibuat seperti ini:

byte[] bytes = Encoding.ASCII.GetBytes(someString);

Anda harus mengubahnya kembali menjadi string seperti ini:

string someString = Encoding.ASCII.GetString(bytes);

Jika Anda dapat menemukan kode yang Anda warisi, pengkodean yang digunakan untuk membuat array byte maka Anda harus mengaturnya.

Timothy Randall
sumber
3
Timothy, saya telah melihat-lihat kode VB dan sepertinya saya tidak dapat menemukan array byte seperti yang telah Anda sebutkan.
nouptime
Pada hasil pencarian Anda, apa jenis properti Properties?
Timothy Randall
Yang bisa saya lihat adalah bahwa ada sejumlah item yang dilampirkan ke Properties sebagai string. Aku tidak yakin apakah itu yang kau tanyakan padaku.
nouptime
16
@AndiAR coba Encoding.UTF8.GetBytes (somestring)
OzBob
1
Untuk situasi saya, saya menemukan bahwa Encoding.Unicode.GetBytes bekerja (tetapi ASCII tidak)
Jeff
106

Pertama-tama, tambahkan System.Textnamespace

using System.Text;

Kemudian gunakan kode ini

string input = "some text"; 
byte[] array = Encoding.ASCII.GetBytes(input);

Berharap untuk memperbaikinya!

Shridhar
sumber
42

Anda juga dapat menggunakan Metode Ekstensi untuk menambahkan metode ke stringjenis seperti di bawah ini:

static class Helper
{
   public static byte[] ToByteArray(this string str)
   {
      return System.Text.Encoding.ASCII.GetBytes(str);
   }
}

Dan gunakan seperti di bawah ini:

string foo = "bla bla";
byte[] result = foo.ToByteArray();
Ali
sumber
12
Saya akan mengganti nama metode itu untuk memasukkan fakta bahwa ia menggunakan pengkodean ASCII. Sesuatu seperti ToASCIIByteArray. Saya benci ketika saya menemukan beberapa perpustakaan yang saya gunakan menggunakan ASCII dan saya menganggap itu menggunakan UTF-8 atau sesuatu yang lebih modern.
T Blank
30
var result = System.Text.Encoding.Unicode.GetBytes(text);
Kuganrajh Rajendran
sumber
3
Ini harus menjadi jawaban yang diterima, seperti jawaban lain menyarankan ASCII, tetapi pengkodeannya adalah Unicode (yang merupakan UTF16) atau UTF8.
Abel
26
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);
}
Eran Yogev
sumber
Ini akan gagal untuk karakter yang termasuk dalam kisaran pasangan pengganti .. GetBytes akan memiliki array byte yang melewatkan satu char normal per pasangan pengganti dari akhirnya. GetString akan memiliki karakter kosong di akhir. Satu-satunya cara kerjanya adalah jika default microsoft adalah UTF32, atau jika karakter dalam kisaran pasangan pengganti tidak diizinkan. Atau ada sesuatu yang tidak saya lihat? Cara yang tepat adalah 'menyandikan' string ke dalam byte.
Gerard ONeill
Benar, untuk rentang yang lebih luas Anda dapat menggunakan sesuatu yang mirip dengan solusi #Timothy Randall: using System; menggunakan System.Text; namespace Contoh {public class Program {public static void Main (string [] args) {string s1 = "Hello World"; string s2 = "שלום עולם"; string s3 = "你好 , 世界!"; Console.WriteLine (Encoding.UTF8.GetString (Encoding.UTF8.GetBytes (s1))); Console.WriteLine (Encoding.UTF8.GetString (Encoding.UTF8.GetBytes (s2))); Console.WriteLine (Encoding.UTF8.GetString (Encoding.UTF8.GetBytes (s3))); }}}
Eran Yogev
17

Mengapa Pengkodean. Kesalahan tidak boleh digunakan ...

@ Randall menggunakan jawaban Encoding.Default, namun Microsoft memunculkan peringatan terhadapnya :

Komputer yang berbeda dapat menggunakan penyandian yang berbeda sebagai default, dan penyandian default dapat berubah pada satu komputer. Jika Anda menggunakan Pengkodean default untuk menyandikan dan mendekode data yang dialirkan antar komputer atau diambil pada waktu yang berbeda di komputer yang sama, itu mungkin menerjemahkan data itu secara tidak benar. Selain itu, penyandian yang dikembalikan oleh properti Default menggunakan fallback paling cocok untuk memetakan karakter yang tidak didukung ke karakter yang didukung oleh halaman kode. Karena alasan ini, tidak disarankan menggunakan pengkodean default. Untuk memastikan bahwa byte yang dikodekan didekodekan dengan benar, Anda harus menggunakan pengkodean Unicode, seperti UTF8Encoding atau UnicodeEncoding. Anda juga bisa menggunakan protokol tingkat yang lebih tinggi untuk memastikan bahwa format yang sama digunakan untuk penyandian dan decoding.

Untuk memeriksa apa pengkodean default, gunakan Encoding.Default.WindowsCodePage(1250 dalam kasus saya - dan sayangnya, tidak ada kelas pengkodean CP1250 yang telah ditentukan, tetapi objek dapat diambil sebagai Encoding.GetEncoding(1250)).

Encoding.ASCII adalah 7bit, jadi tidak berfungsi, dalam kasus saya:

byte[] pass = Encoding.ASCII.GetBytes("šarže");
Console.WriteLine(Encoding.ASCII.GetString(pass)); // ?ar?e

... dan mengapa pengkodean UTF-8 harus digunakan sebagai gantinya ...

Pengkodean default menyesatkan: .NET menggunakan UTF-8 di mana-mana sebagai standar nyata (pengodean 8-bit menjadi usang pada akhir abad ke-20, periksa mis. Console.OutputEncoding.EncodingName*) Sehingga setiap konstanta yang Anda tetapkan dalam kode tersebut adalah UTF-8 yang disandikan secara default - jadi ini harus digunakan kecuali sumber data dalam pengkodean yang berbeda.

* Ini adalah UTF-8 dalam kasus saya yang merupakan kebohongan langsung: chcpdari windows console (cmd) mengembalikan 852 - dan ini tidak boleh diubah, karena perintah sistem yang terlokalisasi (seperti ping) memiliki codepage ini hardcoded

Mengikuti rekomendasi Microsoft:

var utf8 = new UTF8Encoding();
byte[] pass = utf8.GetBytes("šarže");
Console.WriteLine(utf8.GetString(pass)); // šarže

Encoding.UTF8 direkomendasikan oleh orang lain adalah contoh pengkodean uf UTF-8 dan dapat juga digunakan secara langsung atau sebagai

var utf8 = Encoding.UTF8 as UTF8Encoding;

... tapi itu tidak selalu digunakan

Pengkodean untuk byte array seharusnya "hanya berfungsi" di Unicode di negara-negara Barat, tetapi segera setelah Anda memindahkan program Anda ke beberapa daerah yang kurang didukung (seperti di sini di Eropa Timur), itu adalah kekacauan yang nyata: di Republik Ceko Windows default menggunakan (pada tahun 2020!) MS non-standar 852 (alias Latin-2) untuk konsol, 1250 sebagai Windows OEM, UTF-8 (65001) sebagai .NET (dan lain-lain) default baru dan kita harus ingat bahwa beberapa EU 8bit barat data masih dalam 1252, sedangkan standar barat 8bit lama untuk Eropa Timur adalah ISO-8859-2 (alias Latin-2, tapi BUKAN sama Latin-2 seperti 852). Menggunakan ASCII berarti teks yang penuh dengan tahu dan '?' sini. Jadi hingga paruh abad ke-21, harap tetapkan UTF-8 secara eksplisit .

Jan Turoň
sumber
12

Membangun jawaban Ali , saya akan merekomendasikan metode ekstensi yang memungkinkan Anda untuk secara opsional meneruskan pengkodean yang ingin Anda gunakan:

using System.Text;
public static class StringExtensions
{
    /// <summary>
    /// Creates a byte array from the string, using the 
    /// System.Text.Encoding.Default encoding unless another is specified.
    /// </summary>
    public static byte[] ToByteArray(this string str, Encoding encoding = Encoding.Default)
    {
        return encoding.GetBytes(str);
    }
}

Dan gunakan seperti di bawah ini:

string foo = "bla bla";

// default encoding
byte[] default = foo.ToByteArray();

// custom encoding
byte[] unicode = foo.ToByteArray(Encoding.Unicode);
Dan Sinclair
sumber
2
Perhatikan bahwa menggunakan Encoding encoding = Encoding.Defaulthasil dalam kesalahan waktu kompilasi:CS1736 Default parameter value for 'encoding' must be a compile-time constant
Douglas Gaskell
11

Pendekatan berikut hanya akan berfungsi jika karakternya 1 byte. (Unicode default tidak akan berfungsi karena 2 byte)

public static byte[] ToByteArray(string value)
{            
    char[] charArr = value.ToCharArray();
    byte[] bytes = new byte[charArr.Length];
    for (int i = 0; i < charArr.Length; i++)
    {
        byte current = Convert.ToByte(charArr[i]);
        bytes[i] = current;
    }

    return bytes;
}

Menjaga agar tetap sederhana

Mandar Sudame
sumber
chardan stringdefinisi UTF-16.
Tom Blodget
Ya standarnya adalah UTF-16. Saya tidak membuat asumsi tentang Pengkodean dari string input.
Mandar Sudame
Tidak ada teks selain teks yang disandikan. Masukan Anda adalah tipe stringdan oleh karena itu UTF-16. UTF-16 bukan default; tidak ada pilihan tentang itu. Anda kemudian dibagi menjadi char[], unit kode UTF-16. Anda kemudian memanggil Convert.ToByte (Char) , yang kebetulan mengubah U + 0000 menjadi U + 00FF ke ISO-8859-1 , dan mengubah titik-titik kode lain.
Tom Blodget
Masuk akal. Terimakasih atas klarifikasinya. Memperbarui jawaban saya.
Mandar Sudame
1
Saya pikir Anda masih kehilangan beberapa poin penting. Fokus charmenjadi 16 bit dan Convert.ToByte()membuang setengahnya.
Tom Blodget
10

Gunakan ini

byte[] myByte= System.Text.ASCIIEncoding.Default.GetBytes(myString);
alireza amini
sumber
6

Penyempurnaan hasil edit JustinStolle (penggunaan BlockCopy dari Eran Yogev).

Solusi yang diusulkan memang lebih cepat daripada menggunakan Encoding. Masalahnya adalah itu tidak bekerja untuk encoding byte array dengan panjang yang tidak rata. Seperti yang diberikan, itu menimbulkan pengecualian di luar batas. Menambah panjang sebesar 1 meninggalkan trailing byte saat decoding dari string.

Bagi saya, kebutuhan datang ketika saya ingin menyandikan dari DataTableke JSON. Saya sedang mencari cara untuk menyandikan bidang biner menjadi string dan mendekode dari string kembali ke byte[].

Karena itu saya membuat dua kelas - satu yang membungkus solusi di atas (ketika pengkodean dari string tidak apa-apa, karena panjangnya selalu genap), dan yang lain yang menangani byte[]pengodean.

Saya memecahkan masalah panjang yang tidak rata dengan menambahkan satu karakter yang memberitahu saya apakah panjang asli dari array biner itu ganjil ('1') atau genap ('0')

Sebagai berikut:

public static class StringEncoder
{
    static byte[] EncodeToBytes(string str)
    {
        byte[] bytes = new byte[str.Length * sizeof(char)];
        System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
        return bytes;
    }
    static string DecodeToString(byte[] bytes)
    {
        char[] chars = new char[bytes.Length / sizeof(char)];
        System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
        return new string(chars);
    }
}

public static class BytesEncoder
{
    public static string EncodeToString(byte[] bytes)
    {
        bool even = (bytes.Length % 2 == 0);
        char[] chars = new char[1 + bytes.Length / sizeof(char) + (even ? 0 : 1)];
        chars[0] = (even ? '0' : '1');
        System.Buffer.BlockCopy(bytes, 0, chars, 2, bytes.Length);

        return new string(chars);
    }
    public static byte[] DecodeToBytes(string str)
    {
        bool even = str[0] == '0';
        byte[] bytes = new byte[(str.Length - 1) * sizeof(char) + (even ? 0 : -1)];
        char[] chars = str.ToCharArray();
        System.Buffer.BlockCopy(chars, 2, bytes, 0, bytes.Length);

        return bytes;
    }
}
pengguna4726577
sumber
4

Pertanyaan ini telah dijawab berkali-kali, tetapi dengan C # 7.2 dan pengenalan tipe Span, ada cara yang lebih cepat untuk melakukan ini dalam kode yang tidak aman:

public static class StringSupport
{
    private static readonly int _charSize = sizeof(char);

    public static unsafe byte[] GetBytes(string str)
    {
        if (str == null) throw new ArgumentNullException(nameof(str));
        if (str.Length == 0) return new byte[0];

        fixed (char* p = str)
        {
            return new Span<byte>(p, str.Length * _charSize).ToArray();
        }
    }

    public static unsafe string GetString(byte[] bytes)
    {
        if (bytes == null) throw new ArgumentNullException(nameof(bytes));
        if (bytes.Length % _charSize != 0) throw new ArgumentException($"Invalid {nameof(bytes)} length");
        if (bytes.Length == 0) return string.Empty;

        fixed (byte* p = bytes)
        {
            return new string(new Span<char>(p, bytes.Length / _charSize));
        }
    }
}

Perlu diingat bahwa byte mewakili string UTF-16 yang dikodekan (disebut "Unicode" di C # land).

Beberapa pembandingan cepat menunjukkan bahwa metode di atas kira-kira 5x lebih cepat daripada Encoding.Unicode.GetBytes mereka (...) / GetString (...) implementasi untuk string berukuran sedang (30-50 karakter), dan bahkan lebih cepat untuk string yang lebih besar. Metode ini juga tampaknya lebih cepat daripada menggunakan pointer dengan Marshal.Copy (..) atau Buffer.MemoryCopy (...).

Algemist
sumber
4

Jika hasil dari, 'searchResult.Properties ["user"] [0]', adalah sebuah string:

if ( ( searchResult.Properties [ "user" ].Count > 0 ) ) {

   profile.User = System.Text.Encoding.UTF8.GetString ( searchResult.Properties [ "user" ] [ 0 ].ToCharArray ().Select ( character => ( byte ) character ).ToArray () );

}

Poin kuncinya adalah bahwa mengonversi string ke byte [] dapat dilakukan menggunakan LINQ:

.ToCharArray ().Select ( character => ( byte ) character ).ToArray () )

Dan kebalikannya:

.Select ( character => ( char ) character ).ToArray () )
Janus
sumber
3

Adakah yang melihat alasan mengapa tidak melakukan ini?

mystring.Select(Convert.ToByte).ToArray()
Lomithrani
sumber
10
Convert.ToByte(char)tidak bekerja seperti yang Anda pikirkan. Karakter '2'dikonversi ke byte 2, bukan byte yang mewakili karakter '2'. Gunakan mystring.Select(x => (byte)x).ToArray()sebagai gantinya.
Jack
3

Ini yang bekerja untuk saya

byte[] bytes = Convert.FromBase64String(textString);
Mina Matta
sumber
yang hanya berfungsi saat string Anda hanya berisi az, AZ, 0-9, +, /. Tidak ada karakter lain yang diizinkan de.wikipedia.org/wiki/Base64
Blechdose
2

Anda dapat menggunakan MemoryMarshal API untuk melakukan konversi yang sangat cepat dan efisien. Stringsecara implisit akan dilemparkan ke ReadOnlySpan<byte>, sebagai MemoryMarshal.Castmenerima baik Span<byte>atau ReadOnlySpan<byte>sebagai parameter input.

public static class StringExtensions
{
    public static byte[] ToByteArray(this string s) => s.ToByteSpan().ToArray(); //  heap allocation, use only when you cannot operate on spans
    public static ReadOnlySpan<byte> ToByteSpan(this string s) => MemoryMarshal.Cast<char, byte>(s);
}

Patokan berikut menunjukkan perbedaan:

Input: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s,"

|                       Method |       Mean |     Error |    StdDev |  Gen 0 | Gen 1 | Gen 2 | Allocated |
|----------------------------- |-----------:|----------:|----------:|-------:|------:|------:|----------:|
| UsingEncodingUnicodeGetBytes | 160.042 ns | 3.2864 ns | 6.4099 ns | 0.0780 |     - |     - |     328 B |
| UsingMemoryMarshalAndToArray |  31.977 ns | 0.7177 ns | 1.5753 ns | 0.0781 |     - |     - |     328 B |
|           UsingMemoryMarshal |   1.027 ns | 0.0565 ns | 0.1630 ns |      - |     - |     - |         - |
Pawel Maga
sumber
0

Ini bekerja untuk saya, setelah itu saya bisa mengonversi gambar saya di bidang bytea di database saya.

using (MemoryStream s = new MemoryStream(DirEntry.Properties["thumbnailphoto"].Value as byte[]))
{
    return s.ToArray();
}
pengguna10863293
sumber