Jak uzyskać spójną reprezentację bajtów łańcuchów w C# bez ręcznego określania kodowania?

Jak przekonwertować string na byte[] w. Net (C#) bez ręcznego określania określonego kodowania?

Zamierzam zaszyfrować łańcuch. Mogę go zaszyfrować bez konwersji, ale nadal chciałbym wiedzieć, dlaczego kodowanie przychodzi grać tutaj.

Również, dlaczego należy brać pod uwagę kodowanie? Nie mogę po prostu dowiedzieć się, w jakich bajtach łańcuch został zapisany? Dlaczego istnieje zależność od kodowania znaków?

Author: Dragonthoughts, 2009-01-23

30 answers

Wbrew odpowiedziom tutaj, nie musisz się martwić o kodowanie Jeśli bajty nie muszą być interpretowane!

Jak już wspomniałeś, twoim celem jest po prostu "sprawdzenie, w jakich bajtach został zapisany łańcuch znaków".
(I, oczywiście, aby móc ponownie skonstruować łańcuch z bajtów.)

Dla tych celów, szczerze nie rozumiem, dlaczego ludzie mówią ci, że potrzebujesz kodowania. Na pewno nie musisz się martwić o kodowanie tego.

Po prostu zrób to zamiast:

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);
}

Dopóki twój program (lub inne programy) nie próbuje zinterpretować bajtów w jakiś sposób, o czym oczywiście nie wspomniałeś, że zamierzasz to zrobić, to nie ma nic złego w tym podejściu! Martwienie się o kodowanie po prostu komplikuje swoje życie bez prawdziwego powodu.

Dodatkowe korzyści wynikające z tego podejścia:

Nie ma znaczenia, czy łańcuch zawiera nieprawidłowe znaki, ponieważ nadal można uzyskać Dane i zrekonstruować oryginalny ciąg znaków!

Będzie zakodowany i dekodowany tak samo, ponieważ jesteś tylko patrząc na bajty .

Jeśli użyłeś określonego kodowania, to sprawiłoby ci to problemy z kodowaniem / dekodowaniem nieprawidłowych znaków.

 1731
Author: Mehrdad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-18 21:46:49

To zależy od kodowania twojego ciągu znaków ( ASCII, UTF-8,..).

Na przykład:

byte[] b1 = System.Text.Encoding.UTF8.GetBytes (myString);
byte[] b2 = System.Text.Encoding.ASCII.GetBytes (myString);

Mała próbka dlaczego kodowanie ma znaczenie:

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 po prostu nie jest przystosowane do obsługi znaków specjalnych.

Wewnętrznie. NET Framework używa UTF-16 do reprezentowania łańcuchów, więc jeśli chcesz uzyskać dokładne bajty, których używa.NET, użyj System.Text.Encoding.Unicode.GetBytes (...).

Zobacz kodowanie znaków w. NET Framework (MSDN) dla więcej informacji.

 1059
Author: bmotmans,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-24 09:52:05

Przyjęta odpowiedź jest bardzo, bardzo skomplikowana. Użyj dołączonych klas. NET w tym celu:

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);
Nie odkrywaj koła na nowo, jeśli nie musisz...
 250
Author: Erik A. Brandstadmoen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-23 14:32:52
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());
 106
Author: Michael Buen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-26 06:29:52

Należy wziąć pod uwagę kodowanie, ponieważ 1 znak może być reprezentowany przez 1 lub więcej bajtów (do około 6), a różne kodowania będą traktować te bajty inaczej.

Joel ma post na ten temat:

Absolutne Minimum każdy programista absolutnie, pozytywnie musi wiedzieć o Unicode i zestawach znaków (bez wymówek!)

 82
Author: Zhaph - Ben Duguid,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-23 14:03:30

To popularne pytanie. Ważne jest, aby zrozumieć, co zadaje autor pytania i że różni się ono od tego, co jest prawdopodobnie najczęstszą potrzebą. Aby zniechęcić do nadużywania kodu tam, gdzie nie jest on potrzebny, odpowiedziałem na późniejszy pierwszy.

Wspólna Potrzeba

Każdy ciąg znaków ma zestaw znaków i kodowanie. Kiedy konwertujesz obiekt System.String na tablicę System.Byte, nadal masz zestaw znaków i kodowanie. dla większości zastosowań, wiesz, który zestaw znaków i kodowanie, którego potrzebujesz, a. net ułatwia "kopiowanie z konwersją"." wystarczy wybrać odpowiednią klasę Encoding.

// using System.Text;
Encoding.UTF8.GetBytes(".NET String to byte array")

Konwersja może wymagać obsługi przypadków, w których docelowy zestaw znaków lub kodowanie nie obsługuje znaku, który znajduje się w źródle. Masz kilka możliwości: wyjątek, zastąpienie lub pominięcie. Domyślną Polityką jest zastąpienie a '?'.

// using System.Text;
var text = Encoding.ASCII.GetString(Encoding.ASCII.GetBytes("You win €100")); 
                                                      // -> "You win ?100"

Oczywiście konwersje niekoniecznie są bezstratne!

Uwaga: dla System.String zestawu znaków źródłowych jest Unicode.

Jedyną mylącą rzeczą jest to, że. NET używa nazwy zestawu znaków dla nazwy jednego konkretnego kodowania tego zestawu znaków. Encoding.Unicode powinno się nazywać Encoding.UTF16.

to wszystko dla większości zastosowań. Jeśli tego potrzebujesz, przestań tu czytać. Zobacz fajny artykuł Joela Spolsky ' ego jeśli nie rozumiesz, czym jest kodowanie.

Szczególna Potrzeba

Teraz autor zadaje pytanie: "każdy łańcuch jest przechowywany jako tablica bajtów, prawda? Dlaczego nie mogę po prostu mieć tych bajtów?"

On nie chce żadnego nawrócenia.

Z C # spec:

Przetwarzanie znaków i łańcuchów w C# wykorzystuje kodowanie Unicode. Char type reprezentuje jednostkę kodu UTF-16, a string type reprezentuje Sekwencja jednostek kodu UTF-16.

Wiemy więc, że jeśli poprosimy o konwersję null (tj. z UTF-16 na UTF-16), otrzymamy pożądany rezultat:

Encoding.Unicode.GetBytes(".NET String to byte array")

Ale aby uniknąć wspominając o kodowaniu, musimy zrobić to w inny sposób. Jeśli pośredni typ danych jest akceptowalny, istnieje dla niego Skrót pojęciowy:

".NET String to byte array".ToCharArray()

To nie daje nam żądanego typu danych, ale odpowiedź Mehrdada pokazuje, jak przekonwertować tablicę znaków na tablicę bajtów za pomocą BlockCopy . Jednak to kopiuje ciąg dwa razy! I, zbyt jawnie używa kodu specyficznego dla kodowania: datatype System.Char.

Jedynym sposobem, aby dostać się do rzeczywistych bajtów łańcuch jest przechowywany w jest użycie wskaźnika. Instrukcja fixed umożliwia pobranie adresu wartości. Z C # spec:

[dla] wyrażenia typu string, ... inicjalizator oblicza adres pierwszego znaku w łańcuchu.

W tym celu kompilator zapisuje kod pomijając pozostałe części obiektu string za pomocą RuntimeHelpers.OffsetToStringData. Tak więc, aby uzyskać surowe bajty, po prostu Utwórz wskaźnik do łańcucha i skopiuj liczbę potrzebnych bajtów.

// 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;
}

Jak zauważył @ CodesInChaos Na Zewnątrz, wynik zależy od endianess maszyny. Ale autor pytania nie jest tym zainteresowany.

 77
Author: Tom Blodget,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:37

Aby zademonstrować, że odpowiedź Mehrdrada działa, jego podejście może nawet utrzymywać niesparowane postacie zastępcze (z których wielu zrównało się z moją odpowiedzią, ale za co wszyscy są równie winni, np. System.Text.Encoding.UTF8.GetBytes, System.Text.Encoding.Unicode.GetBytes; te metody kodowania nie mogą na przykład utrzymywać wysokich znaków zastępczych d800, a te po prostu zastępują wysokie znaki zastępcze wartością 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);
    }        
}

Wyjście:

T 54
e 65
s 73
t 74
? d800
T 54
e 65
s 73
t 74

Spróbuj z System.Tekst.Kodowanie.UTF8.GetBytes lub System.Tekst.Kodowanie.Unicode.GetBytes , będą one jedynie zastępować wysokie znaki zastępcze wartością fffd

Za każdym razem, gdy pojawia się jakiś ruch w tym pytaniu, wciąż myślę o serializerze (czy to od Microsoftu, czy od komponentu 3rd party), który może utrzymywać ciągi, nawet jeśli zawiera niesparowane znaki zastępcze; od czasu do czasu googluję to: serializacja niesparowany znak zastępczy. NET. nie sprawia, że tracę sen, ale to trochę denerwujące, gdy co jakiś czas ktoś komentuje moją odpowiedź, że jest wadliwa, ale ich odpowiedzi są równie wadliwe, jeśli chodzi o niesparowane postacie zastępcze.

Cholera, Microsoft powinien był użyć System.Buffer.BlockCopy w swoim BinaryFormatter

谢谢!

 37
Author: Michael Buen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:28

Spróbuj tego, dużo mniej kodu:

System.Text.Encoding.UTF8.GetBytes("TEST String");
 36
Author: Nathan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-24 09:58:10

Na pierwszą część twojego pytania (jak zdobyć bajty) odpowiedzieli już inni: poszukaj w przestrzeni nazw System.Text.Encoding.

Odpowiem na twoje kolejne pytanie: dlaczego musisz wybrać kodowanie? Dlaczego nie możesz tego wyciągnąć z samej klasy strun?

Odpowiedź jest w dwóch częściach.

Po pierwsze, bajty używane wewnętrznie przez klasę string nie mają znaczenia , a gdy założysz, że tak, prawdopodobnie wprowadzasz błąd.

Jeśli twój program jest całkowicie w świecie. Net nie musisz się martwić o uzyskanie tablic bajtów dla ciągów, nawet jeśli wysyłasz dane przez sieć. Zamiast tego użyj serializacji. Net, aby martwić się o przesyłanie danych. Nie martw się już o rzeczywiste bajty: program do formalizacji serializacji robi to za Ciebie.

Z drugiej strony, co jeśli wysyłasz te bajty gdzieś, gdzie nie możesz zagwarantować, że będą pobierać dane ze strumienia serializowanego. Net? W tym przypadku zdecydowanie tak trzeba się martwić o kodowanie, bo oczywiście ten zewnętrzny system dba. Tak więc, wewnętrzne bajty używane przez ciąg znaków nie mają znaczenia: musisz wybrać kodowanie, aby można było wyraźnie powiedzieć o tym kodowaniu na końcu odbioru, nawet jeśli jest to to samo kodowanie używane wewnętrznie przez .Net.

Rozumiem, że w tym przypadku możesz preferować użycie rzeczywistych bajtów przechowywanych przez zmienną string w pamięci, jeśli to możliwe, z myślą, że może to zaoszczędzić trochę pracy tworząc strumień bajtów. Jednak powiem ci, że nie jest to po prostu ważne w porównaniu z upewnieniem się, że Twoje wyjście jest zrozumiałe na drugim końcu i aby zagwarantować, że musi być wyraźne z kodowaniem. Dodatkowo, jeśli naprawdę chcesz dopasować wewnętrzne bajty, możesz już wybrać kodowanie Unicode i uzyskać oszczędności wydajności.

Co prowadzi mnie do drugiej części... wybieranie kodowania Unicode na informowanie. Net o używaniu podstawowych bajtów. Potrzebujesz aby wybrać to kodowanie, ponieważ gdy pojawi się jakiś nowy Unicode-Plus, środowisko uruchomieniowe. Net musi być wolne, aby używać tego nowszego, lepszego modelu kodowania bez niszczenia programu. Ale na razie (i na przyszłość) samo wybranie kodowania Unicode daje Ci to, czego chcesz.

Ważne jest również, aby zrozumieć, że Twój ciąg znaków musi zostać przepisany na drut, a to wymaga przynajmniej tłumaczenia wzorca bitowego , nawet jeśli używasz dopasowanego kodowania . Na komputer musi uwzględniać rzeczy takie jak Big vs Little Endian, kolejność bajtów sieci, pakowanie, informacje o sesji itp.

 36
Author: Joel Coehoorn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-25 21:13:44

Przeczytałem wszystkie odpowiedzi i były o kodowaniu lub o serializacji, która wyrzuca niesparowane surogatki.

Jest źle, gdy łańcuch, na przykład, pochodzi z SQL Server gdzie został zbudowany z tablicy bajtów przechowującej na przykład hash hasła. Jeśli coś z niego upuścimy, zachowa nieprawidłowy hash, a jeśli chcemy go przechowywać w XML, chcemy pozostawić go nienaruszonym (ponieważ XML writer zrzuca wyjątek na wszelkie niesparowane zastępcze znaleziska).

Więc używam Base64 kodowanie tablic bajtowych w takich przypadkach, ale hej, w Internecie jest tylko jedno rozwiązanie tego w C#, i ma błąd w nim i jest tylko jeden sposób, więc naprawiłem błąd i procedurę zapisu wstecznego. Oto jesteście, przyszli googlerzy:

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);
}
 22
Author: Gman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-09 08:55:32

Proszę również wyjaśnić, dlaczego należy wziąć pod uwagę kodowanie. Nie mogę po prostu dowiedzieć się, w jakich bajtach łańcuch został zapisany? Skąd ta zależność od kodowania?!!!

Ponieważ nie ma czegoś takiego jak "bajty łańcucha".

Ciąg znaków (lub bardziej ogólnikowo tekst) składa się ze znaków: liter, cyfr i innych symboli. To wszystko. Komputery nie wiedzą jednak nic o znakach; mogą obsługiwać tylko bajty. Dlatego, jeśli chcesz aby zapisać lub przesłać tekst za pomocą komputera, musisz przekształcić znaki na bajty. Jak ty to robisz? Oto, gdzie znajdują się kodowania.

Kodowanie to nic innego jak Konwencja tłumaczenia znaków logicznych na fizyczne bajty. Najprostszym i najbardziej znanym kodowaniem jest ASCII, i to wszystko, czego potrzebujesz, jeśli piszesz w języku angielskim. Dla innych języków będziesz potrzebował bardziej kompletnych kodowań, będąc jednym z smaków Unicode najbezpieczniejszym wyborem w dzisiejszych czasach.

W skrócie, próba "uzyskania bajtów łańcucha bez użycia kodowania" jest tak samo niemożliwa jak "napisanie tekstu bez użycia jakiegokolwiek języka".

Przy okazji, zdecydowanie polecam wam (i każdemu, jeśli o to chodzi) przeczytanie tego małego kawałka mądrości: absolutne Minimum każdy programista absolutnie, pozytywnie musi wiedzieć o Unicode i zestawach znaków (bez wymówek!)

 19
Author: Konamiman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-23 06:19:47

C # to convert a string to a byte array:

public static byte[] StrToByteArray(string str)
{
   System.Text.UTF8Encoding  encoding=new System.Text.UTF8Encoding();
   return encoding.GetBytes(str);
}
 18
Author: Shyam sundar shah,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-12 18:39:11
byte[] strToByteArray(string str)
{
    System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
    return enc.GetBytes(str);
}
 16
Author: gkrogers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-23 13:43:18

Możesz użyć poniższego kodu do konwersji między tablicą znaków i bajtów.

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);
 15
Author: Jarvis Stark,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-09 11:30:51

Nie jestem pewien, ale myślę, że łańcuch przechowuje swoje informacje jako tablicę znaków, co jest nieefektywne w przypadku bajtów. W szczególności, definicja znaku to "reprezentuje znak Unicode".

Weźmy przykładowy przykład:

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));
}

Zwróć uwagę, że odpowiedź Unicode wynosi 14 bajtów w obu przypadkach, podczas gdy odpowiedź UTF-8 wynosi tylko 9 bajtów dla pierwszego i tylko 7 dla drugiego.

Więc jeśli chcesz tylko bajtów używanych przez łańcuch, po prostu użyj Encoding.Unicode, ale będzie to nieefektywne z miejsca do przechowywania.

 11
Author: Ed Marty,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-12 18:38:55

Kluczowy problem polega na tym, że glif w ciągu znaków zajmuje 32 bity (16 bitów dla kodu znakowego), ale bajt ma tylko 8 bitów. Mapowanie jeden do jednego nie istnieje, chyba że ograniczysz się do łańcuchów zawierających tylko znaki ASCII. System.Tekst.Kodowanie ma wiele sposobów na odwzorowanie ciągu znaków na bajt[], musisz wybrać taki, który pozwala uniknąć utraty informacji i który jest łatwy w użyciu przez klienta, gdy musi odwzorować bajt [] z powrotem na ciąg znaków.

Utf8 jest popularnym kodowaniem, jest kompaktowy i nie stratny.

 9
Author: Hans Passant,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-23 14:15:26

Najszybsza droga

public static byte[] GetBytes(string text)
{
    return System.Text.ASCIIEncoding.UTF8.GetBytes(text);
}

EDIT jak skomentował Makotosan, teraz jest to najlepszy sposób:

Encoding.UTF8.GetBytes(text)
 8
Author: Sunrising,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-04 10:31:17

Użycie:

    string text = "string";
    byte[] array = System.Text.Encoding.UTF8.GetBytes(text);

Wynik jest następujący:

[0] = 115
[1] = 116
[2] = 114
[3] = 105
[4] = 110
[5] = 103
 7
Author: mashet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-09 01:22:07

Możesz użyć poniższego kodu, aby przekonwertować string na byte array w. Net

string s_unicode = "abcéabc";
byte[] utf8Bytes = System.Text.Encoding.UTF8.GetBytes(s_unicode);
 5
Author: Shyam sundar shah,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-02 07:39:30

Najbliższym podejściem do pytania OP jest Tom Blodget, który faktycznie wchodzi do obiektu i wydobywa bajty. Mówię najbliżej, ponieważ zależy to od implementacji obiektu String.

"Can't I simply get what bytes the string has been stored in?"

Jasne, ale tu pojawia się podstawowy błąd w pytaniu. Łańcuch jest obiektem, który może mieć interesującą strukturę danych. Wiemy już, że tak, ponieważ pozwala na przechowywanie niesparowanych surogatów. Może zachować długość. Może zachować wskaźnik do każdy z "sparowanych" surogatów umożliwia szybkie liczenie. Itd. Wszystkie te dodatkowe bajty nie są częścią danych znakowych.

To, co chcesz, to bajty każdego znaku w tablicy. I tu wkracza "kodowanie". Domyślnie otrzymasz UTF-16LE. Jeśli nie dbasz o same bajty z wyjątkiem podróży w obie strony, możesz wybrać dowolne kodowanie, w tym "domyślne", i przekonwertować je później (zakładając te same parametry, takie jak to, jakie było domyślne kodowanie, kod punkty, poprawki błędów, rzeczy dozwolone, takie jak niesparowane surogatki itp.

Ale po co zostawiać' kodowanie ' magii? Dlaczego nie określić kodowania, aby wiedzieć, jakie bajty dostaniesz?

"Why is there a dependency on character encodings?"

Kodowanie (w tym kontekście) oznacza po prostu bajty, które reprezentują Twój ciąg znaków. Nie bajty obiektu string. Chciałeś bajtów, w których łańcuch został zapisany . tu pytanie zadano naiwnie. Chciałeś bajty ciągu znaków w ciągłej tablicy, która reprezentuje łańcuch, a nie wszystkie inne dane binarne, które może zawierać obiekt string.

Co oznacza, że sposób przechowywania łańcucha jest nieistotny. Chcesz, aby łańcuch "zakodowany" w bajtach w tablicy bajtów.

Podoba mi się odpowiedź Toma Blogeta, ponieważ zabrał cię w kierunku "bajtów obiektu string". Jest to jednak zależne od implementacji, a ponieważ podgląda wewnętrzne, może być trudno odtworzyć kopię łańcucha.

Odpowiedź Mehrdada jest zła ponieważ wprowadza w błąd na poziomie pojęciowym. Nadal masz zakodowaną listę bajtów. Jego szczególne rozwiązanie pozwala na zachowanie niesparowanych surogatów-jest to zależne od implementacji. Jego konkretne rozwiązanie nie wyświetli dokładnie bajtów łańcucha, jeśli GetBytes domyślnie zwraca łańcuch w UTF-8.

Zmieniłem zdanie co do tego (rozwiązanie Mehrdada) -- to nie jest uzyskanie bajtów łańcucha; raczej uzyskanie bajtów tablicy znaków to zostało stworzone ze Sznurka. Niezależnie od kodowania, typ danych char w c# ma stały rozmiar. Pozwala to na wytworzenie tablicy bajtów o stałej długości i pozwala na odtworzenie tablicy znaków na podstawie rozmiaru tablicy bajtów. Tak więc, gdyby kodowanie było UTF-8, ale każdy znak miał 6 bajtów, aby pomieścić największą wartość utf8, nadal by działało. Więc rzeczywiście-kodowanie znaku nie ma znaczenia.

Ale zastosowano konwersję-każdy znak został umieszczony w fixed size box (typ znaków c#). Jednak to, czym jest ta reprezentacja, nie ma znaczenia, co jest technicznie odpowiedzią na OP. więc -- jeśli i tak zamierzasz się nawrócić... Dlaczego nie "kodować"?

 4
Author: Gerard ONeill,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-01 19:44:31

Wraz z pojawieniem się Span<T> W C# 7.2, kanoniczna technika przechwytywania podstawowej reprezentacji pamięci ciągu znaków w zarządzanej tablicy bajtów to:

byte[] bytes = "rubbish_\u9999_string".AsSpan().AsBytes().ToArray();

Konwersja z powrotem powinna być nie-starterem, ponieważ oznacza to, że w rzeczywistości interpretujesz dane w jakiś sposób, ale ze względu na kompletność: {]}

string s;
unsafe
{
    fixed (char* f = &bytes.AsSpan().NonPortableCast<byte, char>().DangerousGetPinnableReference())
    {
        s = new string(f);
    }
}

Nazwy NonPortableCast i DangerousGetPinnableReference powinny podtrzymywać argument, że prawdopodobnie nie powinieneś tego robić.

zauważ, że praca z Span<T> wymaga zainstalowania systemu .Pakiet Memory NuGet .

Niezależnie od tego, rzeczywiste pierwotne pytanie i kolejne komentarze sugerują, że pamięć bazowa nie jest "interpretowana" (co zakładam, że nie jest modyfikowane ani odczytywane poza potrzebą zapisywania jej jako-jest), wskazując, że niektóre implementacje klasy Stream powinny być używane zamiast rozumowania o danych jako ciągach znaków.

 4
Author: John Rasch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-10 20:21:12

Oto moja niebezpieczna implementacja String do Byte[] konwersji:

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;
}
Jest o wiele szybszy od zaakceptowanego anwsera, nawet jeśli nie jest tak elegancki, jak jest. Oto moje benchmarki stoperów ponad 10000000 iteracji:
[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

Aby go użyć, musisz zaznaczyć "Zezwalaj na niebezpieczny kod" we właściwościach budowania projektu. Jak w. NET Framework 3.5, ta metoda może być również używana jako rozszerzenie łańcucha znaków:

public static unsafe class StringExtensions
{
    public static Byte[] ToByteArray(this String s)
    {
        // Method Code
    }
}
 3
Author: Tommaso Belluzzo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-12 18:38:24

Dwa sposoby:

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();
}

I,

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;
}
Zazwyczaj używam dolnego częściej niż górnego, nie sprawdzałem ich pod kątem szybkości.
 2
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-19 21:03:34
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
 2
Author: user1120193,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-02 11:07:00

Prosty kod z LINQ

string s = "abc"
byte[] b = s.Select(e => (byte)e).ToArray();

EDIT: jak skomentowałem poniżej, nie jest to dobry sposób.

Ale nadal możesz go użyć, aby zrozumieć LINQ z bardziej odpowiednim kodowaniem:

string s = "abc"
byte[] b = s.Cast<byte>().ToArray();
 2
Author: Avlin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-18 10:13:26

Jeśli naprawdę chcesz kopię podstawowych bajtów łańcucha, możesz użyć funkcji takiej jak ta, która następuje. jednak nie powinieneś Czytaj dalej, aby dowiedzieć się, dlaczego.

[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;
}

Ta funkcja szybko dostarczy Ci kopię bajtów znajdujących się pod twoim łańcuchem. Uzyskasz te bajty w jakikolwiek sposób są kodowane w Twoim systemie. To kodowanie jest prawie na pewno UTF-16LE, ale jest to szczegół implementacji, o który nie powinieneś się martwić.

To być bezpieczniejsze, prostsze i bardziej niezawodne wystarczy zadzwonić,

System.Text.Encoding.Unicode.GetBytes()

Najprawdopodobniej da to ten sam wynik, jest łatwiejsze do wpisania, a bajty będą zawsze w obie strony z wywołaniem

System.Text.Encoding.Unicode.GetString()
 2
Author: Jodrell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-25 10:29:12

Po prostu użyj tego:

byte[] myByte= System.Text.ASCIIEncoding.Default.GetBytes(myString);
 2
Author: alireza amini,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-01 01:14:44

Jak przekonwertować łańcuch znaków na bajt [] w. Net (C#) bez ręcznego określania określonego kodowania?

A string W.NET reprezentuje tekst jako sekwencję jednostek kodu UTF-16, więc bajty są już zakodowane w pamięci w UTF-16.

Odpowiedź Mehrdada

Możesz użyć odpowiedzi Mehrdada , ale w rzeczywistości używa kodowania, ponieważ znaki są UTF-16. Nazywa Tochararay, który patrząc na Źródło tworzy char[] i kopiuje pamięć bezpośrednio do niego. Następnie kopiuje dane do tablicy bajtów, która jest również przydzielana. Tak więc pod maską jest kopiowanie podstawowych bajtów dwa razy i przydzielanie tablicy znaków, która nie jest używana po wywołaniu.

Tom Blodget ' s Answer

Odpowiedź Toma Blodgeta jest o 20-30% szybsza niż Mehrdad, ponieważ pomija pośredni etap przydzielania tablicy znaków i kopiowania bajtów do niej, ale wymaga kompilacji z /unsafe opcja. Jeśli absolutnie nie chcesz używać kodowania, myślę, że jest to droga do zrobienia. Jeśli umieścisz swój login szyfrowania wewnątrz bloku fixed, nie musisz nawet przydzielać oddzielnej tablicy bajtów i kopiować do niej bajtów.

Również, dlaczego należy brać pod uwagę kodowanie? Nie mogę po prostu dowiedzieć się, w jakich bajtach łańcuch został zapisany? Dlaczego istnieje zależność od kodowania znaków?

Ponieważ jest to właściwy sposób. string jest abstrakcja.

Używanie kodowania może przysporzyć ci problemów, jeśli masz 'Ciągi' z nieprawidłowymi znakami, ale to nie powinno się zdarzyć. Jeśli otrzymujesz dane do łańcucha z nieprawidłowymi znakami, robisz to źle. Prawdopodobnie powinieneś używać tablicy bajtów lub kodowania Base64 na początek.

Jeśli użyjesz System.Text.Encoding.Unicode, twój kod będzie bardziej odporny. Nie musisz się martwić o endianness systemu, na którym będzie działał Twój kod. Nie musisz się martwić. jeśli następna wersja CLR będzie używać innego wewnętrznego kodowania znaków.

Myślę, że pytanie nie brzmi, dlaczego chcesz się martwić o kodowanie, ale dlaczego chcesz je zignorować i użyć czegoś innego. Kodowanie ma na celu reprezentowanie abstrakcji ciągu znaków w sekwencji bajtów. System.Text.Encoding.Unicode da ci kodowanie w porządku bajtów endyjskich i wykona to samo na każdym systemie, teraz i w przyszłości.

 2
Author: Jason Goemaat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-02 20:51:49

Łańcuch może być konwertowany do tablicy bajtów na kilka różnych sposobów, ze względu na następujący fakt:. NET obsługuje Unicode, a Unicode standaryzuje kilka różnych kodowań zwanych UTFs. Mają różne długości reprezentacji bajtów, ale są równoważne w tym sensie, że gdy łańcuch jest zakodowany, może być zakodowany z powrotem do łańcucha, ale jeśli łańcuch jest zakodowany jednym UTF i dekodowany przy założeniu różnych UTF, jeśli może być zakodowany.

Również. NET obsługuje non-Unicode kodowania, ale nie są one ważne w ogólnym przypadku (będą ważne tylko wtedy, gdy Ograniczony podzbiór punktu kodu Unicode jest używany w rzeczywistym łańcuchu, takim jak ASCII). Wewnętrznie,. NET obsługuje UTF-16, ale do reprezentacji strumienia, UTF-8 jest zwykle używany. Jest to również standard-de-facto dla Internetu.

Nic dziwnego, serializacja łańcuchów do tablicy bajtów i deserializacja jest wspierana przez klasę System.Text.Encoding, która jest klasą abstrakcyjną; jej pochodne obsługują konkretne kodowania: ASCIIEncoding i cztery UTF (System.Text.UnicodeEncoding obsługuje UTF-16)

Ref ten link.

Do serializacji do tablicy bajtów za pomocą System.Text.Encoding.GetBytes. Dla operacji odwrotnej użyj System.Text.Encoding.GetChars. Funkcja ta zwraca tablicę znaków, więc aby otrzymać łańcuch znaków, użyj konstruktora łańcuchów System.String(char[]).
Ref tej strony.

Przykład:

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? :-)
 1
Author: Vijay Singh Rana,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-17 07:33:04

Od byte[] do string:

        return BitConverter.ToString(bytes);
 0
Author: Piero Alberto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-09 01:19:24