Jak przekonwertować string
na byte[]
.NET (C #) bez ręcznego określania konkretnego kodowania?
Mam zamiar zaszyfrować ciąg. Mogę go zaszyfrować bez konwersji, ale nadal chciałbym wiedzieć, dlaczego tutaj kodowanie się pojawia.
Dlaczego warto nawet brać pod uwagę kodowanie? Czy nie mogę po prostu pobrać bajtów, w których zapisano ciąg? Dlaczego istnieje zależność od kodowania znaków?
c#
.net
string
character-encoding
Agnel Kurian
źródło
źródło
Odpowiedzi:
W przeciwieństwie do odpowiedzi tutaj, nie musisz się martwić kodowaniem, jeśli bajty nie muszą być interpretowane!
Jak już wspomniałeś, Twoim celem jest po prostu „zdobycie bajtów, w których łańcuch został zapisany” .
(I oczywiście, aby móc zrekonstruować ciąg z bajtów.)
Jeśli chodzi o te cele, szczerze nie rozumiem, dlaczego ludzie wciąż mówią ci, że potrzebujesz kodowania. Z pewnością NIE musisz się tym martwić o kodowanie.
Po prostu zrób to zamiast tego:
Tak długo, jak twój program (lub inne programy) nie próbuje w jakiś sposób interpretować bajtów, 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 tylko komplikuje życie bez prawdziwego powodu.
Dodatkowe korzyści tego podejścia:
Nie ma znaczenia, czy ciąg zawiera nieprawidłowe znaki, ponieważ nadal możesz uzyskać dane i zrekonstruować oryginalny ciąg!
Zostanie zakodowany i odkodowany tak samo, ponieważ patrzysz tylko na bajty .
Jeśli jednak użyjesz określonego kodowania, sprawiłoby ci to problemy z kodowaniem / dekodowaniem nieprawidłowych znaków.
źródło
GetString
iGetBytes
trzeba je wykonać w systemie z taką samą endianią działania. Więc nie możesz tego użyć, aby uzyskać bajty, które chcesz zmienić w ciąg znaków w innym miejscu. Trudno mi więc wymyślić sytuacje, w których chciałbym tego użyć.To zależy od kodowania twojego łańcucha ( ASCII , UTF-8 , ...).
Na przykład:
Mała próbka, dlaczego kodowanie ma znaczenie:
ASCII po prostu nie jest przystosowany do radzenia sobie ze znakami specjalnymi.
Wewnętrznie .NET Framework używa UTF-16 do reprezentowania ciągów, więc jeśli chcesz uzyskać dokładnie te bajty, których używa .NET, użyj
System.Text.Encoding.Unicode.GetBytes (...)
.Aby uzyskać więcej informacji, zobacz Kodowanie znaków w .NET Framework (MSDN).
źródło
Przyjęta odpowiedź jest bardzo, bardzo skomplikowana. Użyj do tego dołączonych klas .NET:
Nie wymyślaj koła, jeśli nie musisz ...
źródło
System.Text.Encoding.Unicode
być równoważne z odpowiedzią Mehrdada.System.Text.Encoding.Unicode.GetBytes
prawdopodobnie byłby bardziej precyzyjny.źródło
Musisz 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:
źródło
To popularne pytanie. Ważne jest, aby zrozumieć, o co pyta autor pytania, i że różni się on od najprawdopodobniej najczęstszej potrzeby. Aby zniechęcić do niewłaściwego użycia kodu, gdy nie jest on potrzebny, odpowiedziałem najpierw na później.
Wspólna potrzeba
Każdy ciąg ma zestaw znaków i kodowanie. Podczas konwersji
System.String
obiektu na tablicęSystem.Byte
nadal masz zestaw znaków i kodowanie. W przypadku większości zastosowań będziesz wiedział, jakiego zestawu znaków i kodowania potrzebujesz, a .NET ułatwia „kopiowanie z konwersją”. Po prostu wybierz odpowiedniąEncoding
klasę.Konwersja może wymagać obsługi przypadków, w których docelowy zestaw znaków lub kodowanie nie obsługuje znaku znajdującego się w źródle. Masz kilka możliwości: wyjątek, podstawienie lub pominięcie. Domyślną zasadą jest zastąpienie „?”.
Oczywiście konwersje niekoniecznie są bezstratne!
Uwaga: w przypadku
System.String
zestawu znaków źródłowych jest to Unicode.Jedyne mylące jest to, że .NET używa nazwy zestawu znaków dla nazwy jednego konkretnego kodowania tego zestawu znaków.
Encoding.Unicode
powinien zostać nazwanyEncoding.UTF16
.To tyle w przypadku większości zastosowań. Jeśli tego potrzebujesz, przestań czytać tutaj. Zobacz zabawny artykuł Joela Spolsky'ego, jeśli nie rozumiesz, czym jest kodowanie.
Szczególna potrzeba
Teraz autor pytania pyta: „Każdy ciąg jest przechowywany jako tablica bajtów, prawda? Dlaczego nie mogę po prostu mieć tych bajtów?”
On nie chce żadnego nawrócenia.
Ze specyfikacji C # :
Wiemy zatem, że jeśli poprosimy o konwersję zerową (tj. Z UTF-16 na UTF-16), uzyskamy pożądany wynik:
Ale aby uniknąć wzmianki o kodowaniu, musimy zrobić to w inny sposób. Jeśli pośredni typ danych jest dopuszczalny, istnieje do tego skrót koncepcyjny:
To nie daje nam pożądanego typu danych, ale odpowiedź Mehrdada pokazuje, jak przekonwertować tę tablicę Char na tablicę bajtów za pomocą BlockCopy . Spowoduje to jednak skopiowanie ciągu dwukrotnie! I zbyt wyraźnie używa kodu specyficznego dla kodowania: typu danych
System.Char
.Jedynym sposobem na uzyskanie rzeczywistych bajtów, w których przechowywany jest ciąg, jest użycie wskaźnika.
fixed
Zestawienie umożliwia podejmowanie adres wartości. Ze specyfikacji C #:Aby to zrobić, kompilator zapisuje pomijanie kodu nad innymi częściami obiektu ciągu za pomocą
RuntimeHelpers.OffsetToStringData
. Tak więc, aby uzyskać nieprzetworzone bajty, po prostu stwórz wskaźnik do łańcucha i skopiuj potrzebną liczbę bajtów.Jak wskazał @CodesInChaos, wynik zależy od endianizmu maszyny. Ale autor pytania nie jest tym zainteresowany.
źródło
Length
Właściwość [ofString
] zwraca liczbęChar
obiektów w tym przypadku, a nie liczbę znaków Unicode.” Twój przykładowy kod jest zatem poprawny, jak napisano.new String(new []{'\uD800', '\u0030'})
Globalization.SortKey
, wyodrębniaKeyData
i pakuje powstałe bajty z każdego doString
[dwa bajty na znak, najpierw MSB ], wywoływanieString.CompareOrdinal
powstałych ciągów będzie znacznie szybsze niż wywoływanieSortKey.Compare
instancjiSortKey
lub nawet wzywającmemcmp
te przypadki. Biorąc to pod uwagę, zastanawiam się, dlaczegoKeyData
zwracaByte[]
raczej niż aString
?Na pierwszą część twojego pytania (jak zdobyć bajty) odpowiedzieli już inni: spójrz w
System.Text.Encoding
przestrzeń nazw.Odpowiem na twoje dodatkowe pytanie: dlaczego musisz wybrać kodowanie? Dlaczego nie możesz tego uzyskać z samej klasy strun?
Odpowiedź składa się z dwóch części.
Przede wszystkim bajty używane wewnętrznie przez klasę łańcuchową nie mają znaczenia , a gdy tylko zakładasz, że tak, prawdopodobnie wprowadzasz błąd.
Jeśli twój program znajduje się całkowicie w świecie .Net, nie musisz się w ogóle 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ę przesyłaniem danych. Nie musisz się już martwić o rzeczywiste bajty: formatyzator serializacji robi to za Ciebie.
Z drugiej strony, co jeśli wysyłasz te bajty gdzieś, co nie jest gwarantowane, że pobierze dane z serializowanego strumienia .Net? W takim przypadku zdecydowanie musisz martwić się o kodowanie, ponieważ oczywiście ten zewnętrzny system ma znaczenie. Zatem znowu bajty wewnętrzne używane przez ciąg nie mają znaczenia: musisz wybrać kodowanie, abyś mógł wyraźnie powiedzieć o tym kodowaniu po stronie odbierającej, nawet jeśli jest to to samo kodowanie używane wewnętrznie przez .Net.
Rozumiem, że w tym przypadku wolisz używać rzeczywistych bajtów przechowywanych w pamięci zmiennej ciągowej, o ile to możliwe, z pomysłem, że może to zaoszczędzić trochę pracy podczas tworzenia strumienia bajtów. Jednak przekazuję wam to, że nie jest to po prostu ważne w porównaniu do upewnienia się, że dane wyjściowe są zrozumiane na drugim końcu, i do zagwarantowania, że trzeba jawnie kodować. Ponadto, jeśli naprawdę chcesz dopasować bajty wewnętrzne, możesz już po prostu wybrać
Unicode
kodowanie i uzyskać oszczędności wydajności.Który doprowadza mnie do drugiej części ... wybranie
Unicode
kodowania jest mówienie .Net używać bajtów bazowych. Musisz wybrać to kodowanie, ponieważ gdy pojawi się nowy, unikatowy kod Unicode-Plus, środowisko wykonawcze .Net musi mieć swobodę korzystania z tego nowszego, lepszego modelu kodowania bez zepsucia programu. Ale na razie (i dająca się przewidzieć przyszłość) wybranie kodowania Unicode daje to, czego chcesz.Ważne jest również, aby zrozumieć, że łańcuch musi zostać przepisany na drut, a to wymaga co najmniej tłumaczenia wzoru bitowego, nawet jeśli używasz pasującego kodowania . Komputer musi uwzględniać takie rzeczy, jak Big vs. Little Endian, kolejność bajtów w sieci, pakietowanie, informacje o sesji itp.
źródło
Wystarczy wykazać, że dźwięk Mehrdrad za odpowiedź dzieła, jego podejście może nawet trwać do niesparowanych znaków zastępczych (z których wiele było wyrównane przed moją odpowiedź, ale z których wszyscy są jednakowo winni, na przykład
System.Text.Encoding.UTF8.GetBytes
,System.Text.Encoding.Unicode.GetBytes
; te metody kodowania nie mogą utrzymywać wysoką surogat znakid800
na przykład, i te właśnie jedynie wymienić wysokie znaków zastępczych z wartościfffd
):Wynik:
Spróbuj tego z System.Text.Encoding.UTF8.GetBytes lub System.Text.Encoding.Unicode.GetBytes , po prostu zastąpią one znaki o wysokiej wartości zastępczej wartością fffd
Za każdym razem, gdy pojawia się ruch w tym pytaniu, wciąż myślę o serializatorze (czy to z Microsoft, czy z komponentu innej firmy), który może utrzymywać ciągi znaków, nawet jeśli zawiera niesparowane znaki zastępcze; Przeglądam to od czasu do czasu: serializacja niesparowanej postaci zastępczej .NET . Nie sprawia to, że tracę sen, ale czasami denerwuje mnie to, że ktoś komentuje moją odpowiedź, że jest wadliwa, ale ich odpowiedzi są równie błędne, jeśli chodzi o niesparowane postacie zastępcze.
Cholera, Microsoft powinien był po prostu użyć
System.Buffer.BlockCopy
w swoimBinaryFormatter
ツ谢谢!
źródło
System.Buffer.BlockCopy
wewnętrznie, wszystkie argumenty popierające kodowanie będą dyskusyjneFFFD
tego znaku. Jeśli chcesz wykonywać ręczne operacje na łańcuchach, użyj char [] zgodnie z zaleceniami.System.String
jest niezmienną sekwencjąChar
; .NET zawsze zezwalałString
na konstruowanie dowolnego obiektuChar[]
i eksportowanie jego zawartości doChar[]
zawierających te same wartości, nawet jeśli oryginałChar[]
zawiera niesparowane odpowiedniki.Spróbuj tego, o wiele mniej kodu:
źródło
System.Text.Encoding.UTF8.GetBytes("Árvíztűrő tükörfúrógép);
i płacz! Będzie działać, aleSystem.Text.Encoding.UTF8.GetBytes("Árvíztűrő tükörfúrógép").Length != System.Text.Encoding.UTF8.GetBytes("Arvizturo tukorfurogep").Length
jednocześnie"Árvíztűrő tükörfúrógép".Length == "Arvizturo tukorfurogep".Length
Cóż, przeczytałem wszystkie odpowiedzi i dotyczyły one kodowania lub serializacji, która odrzuca niesparowane zastępcze.
Jest źle, gdy na przykład ciąg pochodzi z SQL Server, gdzie został zbudowany z tablicy bajtów przechowującej, na przykład hash hasła. Jeśli coś z niego usuniemy, będzie przechowywać niepoprawny skrót, a jeśli chcemy przechowywać go w formacie XML, chcemy pozostawić go nienaruszonego (ponieważ program piszący XML odrzuca wyjątek dla każdego niesparowanego znalezionego surogatu).
Więc używam kodowania bajtów tablic Base64 w takich przypadkach, ale hej, w Internecie jest tylko jedno rozwiązanie tego w C #, i ma błąd i jest tylko jeden sposób, więc naprawiłem błąd i odpisałem procedura. Oto przyszli pracownicy Google:
źródło
Convert.ToBase64String(arr);
do konwersji base64byte[] (data) <-> string (serialized data to store in XML file)
. Jednak, aby uzyskać wstępnąbyte[] (data)
Musiałem coś zrobić zString
zawartej binarnych danych (jest to droga MSSQL wróciła mi go). SO powyższe funkcje są dlaString (binary data) <-> byte[] (easy accessible binary data)
.Ponieważ nie ma czegoś takiego jak „bajty ciągu”.
Ciąg (lub bardziej ogólnie tekst) składa się ze znaków: liter, cyfr i innych symboli. To wszystko. Komputery jednak nie wiedzą nic o postaciach; mogą obsługiwać tylko bajty. Dlatego jeśli chcesz przechowywać lub przesyłać tekst za pomocą komputera, musisz przekształcić znaki w bajty. Jak to robisz? Oto, gdzie pojawiają się kodowania.
Kodowanie jest niczym innym jak konwencją służącą do tłumaczenia znaków logicznych na bajty fizyczne. Najprostszym i najlepiej znanym kodowaniem jest ASCII i to wszystko, czego potrzebujesz, jeśli piszesz po angielsku. W przypadku innych języków potrzebne będą bardziej kompletne kodowania, ponieważ jest to jeden z najbezpieczniejszych obecnie wyborów Unicode.
Krótko mówiąc, próba „pobrania bajtów ciągu bez użycia kodowania” jest tak niemożliwa, jak „napisanie tekstu bez użycia języka”.
Nawiasem mówiąc, zdecydowanie polecam wam (i każdemu, jeśli o to chodzi) przeczytanie tej małej mądrości: Absolutne minimum Każdy programista Absolutnie, pozytywnie musi wiedzieć o Unicode i zestawach znaków (bez wymówek!)
źródło
C # do konwersji tablicy
string
nabyte
tablicę:źródło
źródło
Możesz użyć następującego kodu do konwersji między tablicą łańcuchów znaków i bajtów.
źródło
Wraz z nadejściem
Span<T>
wersji C # 7.2 kanoniczną techniką przechwytywania reprezentacji pamięci w łańcuchu w zarządzanej tablicy bajtów jest:Konwersja powinna być początkowa, ponieważ oznacza to, że faktycznie interpretujesz dane, ale ze względu na kompletność:
Imiona
NonPortableCast
i nazwiska orazDangerousGetPinnableReference
argument, że prawdopodobnie nie powinieneś tego robić.Pamiętaj, że praca z
Span<T>
wymaga instalacji pakietu System.Memory NuGet .Niezależnie od tego, aktualne oryginalne pytania i komentarze uzupełniające sugerują, że pamięć podstawowa nie jest „interpretowana” (co, jak zakładam, oznacza, że nie jest modyfikowana ani czytana poza koniecznością zapisania jej w niezmienionej postaci), co wskazuje, że niektóre implementacje
Stream
klasy powinny być używane zamiast wnioskowania o danych jako ciągach.źródło
Nie jestem pewien, ale myślę, że ciąg przechowuje informacje jako tablicę znaków, co jest nieefektywne w bajtach. W szczególności definicja Char to „Reprezentuje znak Unicode”.
weź przykładową próbkę:
Zwróć uwagę, że odpowiedź Unicode wynosi 14 bajtów w obu przypadkach, podczas gdy odpowiedź UTF-8 ma tylko 9 bajtów dla pierwszego i tylko 7 dla drugiego.
Więc jeśli chcesz tylko bajtów używanych przez ciąg, po prostu użyj
Encoding.Unicode
, ale będzie to nieefektywne w przypadku przestrzeni dyskowej.źródło
Kluczową kwestią jest to, że glif w ciągu zajmuje 32 bity (16 bitów w kodzie znaków), ale bajt ma tylko 8 bitów do zaoszczędzenia. Mapowanie jeden do jednego nie istnieje, chyba że ograniczysz się do ciągów zawierających tylko znaki ASCII. System.Text.Encoding ma wiele sposobów mapowania ciągu na bajt [], musisz wybrać taki, który pozwala uniknąć utraty informacji i który jest łatwy w użyciu dla twojego klienta, gdy potrzebuje on zamapować bajt [] z powrotem na ciąg .
Utf8 jest popularnym kodowaniem, jest kompaktowy i nie jest stratny.
źródło
Posługiwać się:
Wynik to:
źródło
Najszybsza droga
EDYCJA jak skomentował Makotosan, jest to teraz najlepszy sposób:
źródło
Ciąg w .NET reprezentuje tekst jako ciąg znaków UTF-16 jednostek kodowych, tak bajty są kodowane w pamięci w UTF-16 już.
Odpowiedź Mehrdada
Możesz użyć odpowiedzi Mehrdada , ale w rzeczywistości używa ona kodowania, ponieważ znaki to UTF-16. Wywołuje ToCharArray, który patrząc na źródło tworzy a
char[]
i bezpośrednio kopiuje do niego pamięć. Następnie kopiuje dane do przydzielonej tablicy bajtów. Więc pod maską kopiuje dwa razy leżące u podstaw bajty i przydziela tablicę znaków, która nie jest używana po wywołaniu.Odpowiedź Toma Blodgeta
Odpowiedź Toma Blodgeta jest o 20-30% szybsza niż Mehrdad, ponieważ pomija etap pośredni przydzielania tablicy znaków i kopiowania do niej bajtów, ale wymaga kompilacji z
/unsafe
opcją. Jeśli absolutnie nie chcesz używać kodowania, myślę, że to jest właściwa droga. Jeśli umieścisz login szyfrowania wfixed
bloku, nie musisz nawet przydzielać osobnej tablicy bajtów i kopiować do niej bajty.Ponieważ to jest właściwy sposób, aby to zrobić.
string
jest abstrakcją.Korzystanie z kodowania może sprawić kłopoty, jeśli masz „ciągi znaków” z nieprawidłowymi znakami, ale to nie powinno się zdarzyć. Jeśli dostajesz dane do łańcucha z nieprawidłowymi znakami, robisz to źle. Najpierw prawdopodobnie powinieneś użyć tablicy bajtów lub kodowania Base64.
Jeśli go użyjesz
System.Text.Encoding.Unicode
, Twój kod będzie bardziej odporny. Nie musisz się martwić o endianizm 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 dotyczy tego, dlaczego chcesz się martwić kodowaniem, ale dlaczego chcesz go zignorować i użyć czegoś innego. Kodowanie ma reprezentować abstrakcję ciągu w sekwencji bajtów.
System.Text.Encoding.Unicode
da ci trochę kodowania kolejności bajtów endian i będzie działać tak samo na każdym systemie, teraz iw przyszłości.źródło
Najbliższym podejściem do pytania PO jest pytanie Toma Blodgeta, które faktycznie wchodzi do obiektu i wyodrębnia bajty. Mówię najbliżej, ponieważ zależy to od implementacji obiektu String.
Jasne, ale tutaj 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ż umożliwia przechowywanie niesparowanych parametrów zastępczych. Może przechowywać długość. Może utrzymywać wskaźnik do każdego z „sparowanych” zastępców, umożliwiając szybkie liczenie. Itd. Wszystkie te dodatkowe bajty nie są częścią danych znakowych.
To, czego chcesz, to bajty każdego znaku w tablicy. I tu właśnie pojawia się „kodowanie”. Domyślnie otrzymasz UTF-16LE. Jeśli nie zależy ci na samych bajtach oprócz podróży w obie strony, możesz wybrać dowolne kodowanie, w tym „domyślne”, i przekonwertować je później (zakładając takie same parametry, jak domyślne kodowanie, punkty kodowe, poprawki błędów , dozwolone rzeczy, takie jak niesparowane zastępcze itp.
Ale dlaczego pozostawić „kodowanie” magii? Dlaczego nie podać kodowania, aby wiedzieć, jakie bajty otrzymasz?
Kodowanie (w tym kontekście) oznacza po prostu bajty reprezentujące łańcuch. Nie bajty obiektu ciągu. Chcieliście bajtów, w których zapisano ciąg znaków - tutaj naiwnie zadano pytanie. Chcieliście bajtów łańcucha w ciągłej tablicy, która reprezentuje łańcuch, a nie wszystkich innych danych binarnych, które może zawierać obiekt łańcucha.
Co oznacza, że sposób przechowywania łańcucha nie ma znaczenia. Chcesz ciąg „Zakodowany” w bajtach w tablicy bajtów.
Podoba mi się odpowiedź Toma Blogeta, ponieważ poprowadził cię w kierunku „bajtów obiektu sznurkowego”. Jest to jednak zależne od implementacji, a ponieważ zagląda do wewnętrznych elementów, odtworzenie kopii łańcucha może być trudne.
Odpowiedź Mehrdada jest błędna, ponieważ wprowadza w błąd na poziomie koncepcyjnym. Nadal masz listę bajtów, zakodowanych. Jego szczególne rozwiązanie pozwala na zachowanie niesparowanych parametrów zastępczych - zależy to od implementacji. Jego szczególne rozwiązanie nie wygenerowałoby bajtów łańcucha dokładnie, gdyby
GetBytes
domyślnie zwrócił ciąg w UTF-8.Zmieniłem zdanie na ten temat (rozwiązanie Mehrdada) - nie pobiera bajtów ciągu; raczej pobiera bajty tablicy znaków, która została utworzona z ciągu. Niezależnie od kodowania typ danych char w c # ma stały rozmiar. Pozwala to na utworzenie tablicy bajtów o stałej długości i pozwala na odtworzenie tablicy znaków na podstawie rozmiaru tablicy bajtów. Więc jeśli kodowanie to UTF-8, ale każdy znak ma 6 bajtów, aby pomieścić największą wartość utf8, nadal by działał. Tak więc - kodowanie postaci nie ma znaczenia.
Zastosowano jednak konwersję - każda postać została umieszczona w polu o stałym rozmiarze (typ znaku c #). Jednak to, czym jest ta reprezentacja, nie ma znaczenia, co jest technicznie odpowiedzią na PO. Więc - jeśli i tak zamierzasz dokonać konwersji ... Dlaczego nie „zakodować”?
źródło
&(Char) 55906
&(Char) 55655
. Więc możesz się mylić, a odpowiedź Mehrdada to bezpieczna konwersja bez zastanawiania się, jakiego rodzaju kodowania się używa.Możesz użyć następującego kodu, aby przekonwertować plik
string
nabyte array
.NETźródło
Jeśli naprawdę chcesz kopii bazowych bajtów ciągu, możesz użyć funkcji takiej jak następująca. Nie powinieneś jednak czytać dalej, aby dowiedzieć się, dlaczego.
Ta funkcja dość szybko da ci kopię bajtów leżącą u podstaw łańcucha. Otrzymasz te bajty w dowolny sposób, w jaki 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ć.
Dzwonienie byłoby bezpieczniejsze, prostsze i bardziej niezawodne ,
Najprawdopodobniej da to ten sam wynik, łatwiej jest pisać, a bajty zawsze będą w obie strony z wywołaniem
źródło
Oto moja niebezpieczne wdrożenie
String
doByte[]
nawrócenia:Jest o wiele szybszy niż akceptowany anwser, nawet jeśli nie jest tak elegancki, jak to jest. Oto moje testy porównawcze stopera z ponad 10000000 iteracji:
Aby go użyć, musisz zaznaczyć „Zezwól na niebezpieczny kod” we właściwościach kompilacji projektu. Zgodnie z .NET Framework 3.5, ta metoda może być również używana jako rozszerzenie String:
źródło
RuntimeHelpers.OffsetToStringData
wielokrotności 8 w Itanium wersjach .NET? Ponieważ w przeciwnym razie to się nie powiedzie z powodu nieprzystosowanych odczytów.memcpy
? stackoverflow.com/a/27124232/659190Po prostu użyj tego:
źródło
System.Text.ASCIIEncoding.Default.GetBytes("Árvíztűrő tükörfúrógép.").ToString();
zwróci"Árvizturo tukörfurogép."
utracone informacje, których nie można odzyskać. (I nie wspomniałem jeszcze o językach azjatyckich, w których stracisz wszystkie znaki).Ciąg może zostać przekonwertowany na tablicę bajtów na kilka różnych sposobów, z powodu następującego faktu: .NET obsługuje Unicode, a Unicode standaryzuje kilka kodowań różnic nazywanych UTF. Mają różne długości reprezentacji bajtów, ale są równoważne w tym sensie, że gdy łańcuch jest kodowany, może być kodowany z powrotem do łańcucha, ale jeśli łańcuch jest kodowany za pomocą jednego UTF i dekodowany przy założeniu innego UTF, jeśli można go wkręcić w górę.
Ponadto .NET obsługuje kodowanie inne niż Unicode, ale nie są one poprawne w ogólnym przypadku (będą ważne tylko wtedy, gdy w rzeczywistym ciągu znaków, takim jak ASCII, zostanie zastosowany ograniczony podzbiór punktu kodowego Unicode). Wewnętrznie .NET obsługuje UTF-16, ale do reprezentacji strumienia zwykle używa się UTF-8. Jest to również de facto standard dla Internetu.
Nic dziwnego, że serializacja łańcucha na tablicę bajtów i deserializacja jest obsługiwana przez klasę
System.Text.Encoding
, która jest klasą abstrakcyjną; jego klasy pochodne obsługują konkretne kodowanie:ASCIIEncoding
i cztery UTF (System.Text.UnicodeEncoding
obsługuje UTF-16)Sprawdź ten link.
Do serializacji do tablicy bajtów za pomocą
System.Text.Encoding.GetBytes
. Do operacji odwrotnej użyjSystem.Text.Encoding.GetChars
. Ta funkcja zwraca tablicę znaków, więc aby uzyskać ciąg, użyj konstruktora ciągówSystem.String(char[])
.Odwołaj się do tej strony.
Przykład:
źródło
To zależy od tego, dla których bajtów chcesz
Jest tak, ponieważ, jak trafnie powiedział Tyler : „Ciągi nie są czystymi danymi. Mają także informacje ”. W takim przypadku informacja jest kodowaniem przyjętym podczas tworzenia łańcucha.
Zakładając, że masz dane binarne (zamiast tekstu) zapisane w ciągu
Jest to oparte na komentarzu OP do jego własnego pytania i jest to prawidłowe pytanie, jeśli rozumiem wskazówki OP dotyczące przypadku użycia.
Przechowywanie danych binarnych w ciągach jest prawdopodobnie niewłaściwym podejściem ze względu na przyjęte wyżej kodowanie! Jakikolwiek program lub biblioteka przechowywał te dane binarne w
string
(zamiastbyte[]
tablicy, która byłaby bardziej odpowiednia), już przegrał bitwę przed jej rozpoczęciem. Jeśli wysyłają bajty do Ciebie w żądaniu / odpowiedzi REST lub czegokolwiek, co musi przesyłać ciągi, Base64 byłoby właściwym podejściem.Jeśli masz ciąg tekstowy z nieznanym kodowaniem
Wszyscy inni odpowiedzieli niepoprawnie na to nieprawidłowe pytanie.
Jeśli ciąg znaków wygląda dobrze w obecnej postaci, po prostu wybierz kodowanie (najlepiej zaczynające się od UTF), użyj odpowiedniej
System.Text.Encoding.???.GetBytes()
funkcji i powiedz komuś, kto podaje bajty, które kodowanie wybrałeś.źródło
Na pytanie, co zamierzasz zrobić z bajtami, odpowiedziałeś :
Niezależnie od tego, czy zamierzasz wysłać te zaszyfrowane dane przez sieć, załadować je później z powrotem do pamięci, czy też przesłać do innego procesu, najwyraźniej zamierzasz je odszyfrować w pewnym momencie. W takim przypadku odpowiedź brzmi: definiujesz protokół komunikacyjny. Protokół komunikacyjny nie powinien być definiowany w kategoriach szczegółów implementacyjnych języka programowania i powiązanego z nim środowiska wykonawczego. Istnieje kilka powodów:
Aby komunikować się (w przyszłości z całkowicie innym procesem lub z tym samym programem), musisz ściśle zdefiniować swój protokół, aby zminimalizować trudność z jego obsługą lub przypadkowym tworzeniem błędów. W zależności od wewnętrznej reprezentacji .NET nie jest to ścisła, jasna, a nawet gwarantowana spójna definicja. Standardowe kodowanie to ścisła definicja, która nie zawiedzie Cię w przyszłości.
Innymi słowy, nie można spełnić wymagań dotyczących spójności bez podania kodowania.
Z pewnością możesz zdecydować się na użycie UTF-16 bezpośrednio, jeśli okaże się, że proces działa znacznie lepiej, ponieważ .NET używa go wewnętrznie lub z dowolnego innego powodu, ale musisz wybrać to kodowanie jawnie i wykonać te konwersje jawnie w kodzie, a nie w zależności na wewnętrznej implementacji .NET.
Wybierz kodowanie i użyj go:
Jak widać, użycie wbudowanych obiektów kodujących jest w rzeczywistości mniejszym kodem niż zaimplementowanie własnych metod odczytu / zapisu.
źródło
Dwie drogi:
I,
Zazwyczaj używam dolnej części częściej niż górnej, nie testowałem ich pod kątem szybkości.
źródło
źródło