특정 인코딩을 수동으로 지정하지 않고 string
a byte[]
를 .NET (C #)으로 변환하려면 어떻게해야 합니까?
문자열을 암호화하겠습니다. 변환하지 않고 암호화 할 수는 있지만 여전히 인코딩이 왜 작동하는지 알고 싶습니다.
또한 인코딩을 고려해야하는 이유는 무엇입니까? 문자열이 저장된 바이트를 간단히 얻을 수 없습니까? 문자 인코딩에 의존하는 이유는 무엇입니까?
특정 인코딩을 수동으로 지정하지 않고 string
a byte[]
를 .NET (C #)으로 변환하려면 어떻게해야 합니까?
문자열을 암호화하겠습니다. 변환하지 않고 암호화 할 수는 있지만 여전히 인코딩이 왜 작동하는지 알고 싶습니다.
또한 인코딩을 고려해야하는 이유는 무엇입니까? 문자열이 저장된 바이트를 간단히 얻을 수 없습니까? 문자 인코딩에 의존하는 이유는 무엇입니까?
답변:
앞에서 언급했듯이 목표는 단순히 "문자열이 저장된 바이트 수 "를 얻는 것 입니다.
(물론 바이트에서 문자열을 재구성 할 수도 있습니다.)
대신이 작업을 수행하십시오.
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);
}
프로그램 (또는 다른 프로그램)이 어떻게 든 바이트 를 해석 하려고 시도하지 않는 한 , 분명히 할 의도는 없지만 이 방법 에는 아무런 문제 가 없습니다 ! 인코딩에 대해 걱정하면 실제 이유없이 삶이 더 복잡해집니다.
bytes 만보 고 있기 때문에 똑같이 인코딩되고 디코딩 됩니다 .
그러나 특정 인코딩을 사용한 경우 유효하지 않은 문자를 인코딩 / 디코딩하는 데 문제가있을 수 있습니다.
GetString
와 GetBytes
작업에 동일한 엔디안있는 시스템에서 실행해야합니다. 따라서 다른 곳에서 문자열로 바꾸려는 바이트를 얻는 데 이것을 사용할 수 없습니다. 그래서 저는 이것을 사용하고 싶은 상황을 생각해 내기가 어렵습니다.
문자열 인코딩 ( ASCII , UTF-8 , ...) 에 따라 다릅니다 .
예를 들면 다음과 같습니다.
byte[] b1 = System.Text.Encoding.UTF8.GetBytes (myString);
byte[] b2 = System.Text.Encoding.ASCII.GetBytes (myString);
인코딩이 중요한 이유는 다음과 같습니다.
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는 단순히 특수 문자를 처리 할 수 없습니다.
내부적으로 .NET 프레임 워크는 UTF-16 을 사용 하여 문자열을 나타내므로 .NET에서 사용하는 정확한 바이트를 얻으려면을 사용하십시오 System.Text.Encoding.Unicode.GetBytes (...)
.
자세한 내용 은 .NET Framework (MSDN) 의 문자 인코딩 을 참조하십시오.
허용되는 답변은 매우 복잡합니다. 이를 위해 포함 된 .NET 클래스를 사용하십시오.
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);
당신이 필요하지 않은 경우 바퀴를 재발 명하지 마십시오 ...
System.Text.Encoding.Unicode
Mehrdad의 답변과 동일 해야합니다 .
System.Text.Encoding.Unicode.GetBytes
아마도 더 정확할 것입니다.
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());
1 개의 문자는 1 개 이상의 바이트 (최대 약 6 개) 로 표현 될 수 있으므로 인코딩을 고려해야 하며, 다른 인코딩은 이러한 바이트를 다르게 취급합니다.
Joel은 이것에 대해 글을 올렸습니다 :
절대적으로 모든 소프트웨어 개발자는 반드시 유니 코드 및 문자 집합에 대해 반드시 알아야합니다 (변명 없음).
이것은 인기있는 질문입니다. 질문 작성자가 요구하는 내용을 이해하고 가장 일반적인 요구와 다른 점을 이해하는 것이 중요합니다. 필요하지 않은 코드의 오용을 막기 위해 나중에 먼저 답변했습니다.
모든 문자열에는 문자 세트와 인코딩이 있습니다. System.String
객체를 배열 로 변환 System.Byte
해도 여전히 문자 세트와 인코딩이 있습니다. 대부분의 용도에서 필요한 문자 세트와 인코딩을 알고 .NET을 사용하면 "변환하여 복사"하는 것이 간단 해집니다. 적절한 Encoding
수업을 선택하십시오 .
// using System.Text;
Encoding.UTF8.GetBytes(".NET String to byte array")
변환은 대상 문자 세트 또는 인코딩이 소스에있는 문자를 지원하지 않는 경우를 처리해야합니다. 예외, 대체 또는 건너 뛰기 중에서 선택할 수 있습니다. 기본 정책은 '?'를 대체하는 것입니다.
// using System.Text;
var text = Encoding.ASCII.GetString(Encoding.ASCII.GetBytes("You win €100"));
// -> "You win ?100"
분명히, 전환이 반드시 손실이있는 것은 아닙니다!
참고 : System.String
소스 문자 세트의 경우 유니 코드입니다.
혼란스러운 점은 .NET이 해당 문자 세트의 특정 인코딩 이름에 문자 세트 이름을 사용한다는 것입니다. Encoding.Unicode
호출되어야합니다 Encoding.UTF16
.
그게 대부분의 사용법입니다. 그것이 필요한 것이라면 여기에서 읽기를 중단하십시오. 인코딩이 무엇인지 이해하지 못하는 경우 재미있는 Joel Spolsky 기사를 참조하십시오 .
이제 질문 작성자는 "모든 문자열이 바이트 배열로 저장됩니다. 왜 그런 바이트를 가질 수 없습니까?"
그는 어떤 전환도 원하지 않습니다.
로부터 C #을 사양 :
C #의 문자 및 문자열 처리는 유니 코드 인코딩을 사용합니다. char 유형은 UTF-16 코드 단위를 나타내고 문자열 유형은 일련의 UTF-16 코드 단위를 나타냅니다.
따라서 null 변환을 요청하면 (예 : UTF-16에서 UTF-16으로) 원하는 결과를 얻을 수 있습니다.
Encoding.Unicode.GetBytes(".NET String to byte array")
그러나 인코딩에 대한 언급을 피하려면 다른 방법으로 인코딩해야합니다. 중간 데이터 유형이 허용 가능한 경우 이에 대한 개념적 지름길이 있습니다.
".NET String to byte array".ToCharArray()
그것은 우리에게 원하는 데이터 유형을 얻지 못하지만 Mehrdad의 대답 은 BlockCopy를 사용 하여이 Char 배열을 바이트 배열로 변환하는 방법을 보여줍니다 . 그러나 이것은 문자열을 두 번 복사합니다! 또한 인코딩 관련 코드 인 datatype도 명시 적으로 사용합니다 System.Char
.
문자열이 저장된 실제 바이트를 얻는 유일한 방법은 포인터를 사용하는 것입니다. 이 fixed
문장은 값의 주소를 취할 수 있습니다. C # 사양에서 :
[문자열] 유형의 표현식의 경우, 초기화 프로그램은 문자열에서 첫 번째 문자의 주소를 계산합니다.
그렇게하기 위해 컴파일러는을 사용하여 문자열 객체의 다른 부분을 건너 뛰는 코드를 작성합니다 RuntimeHelpers.OffsetToStringData
. 따라서 원시 바이트를 얻으려면 문자열에 대한 포인터를 만들고 필요한 바이트 수를 복사하십시오.
// 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;
}
@CodesInChaos가 지적했듯이 결과는 기계의 엔디안에 달려 있습니다. 그러나 질문 저자는 그것에 관심이 없습니다.
Length
[of String
] 속성 Char
은이 인스턴스에서 유니 코드 문자 수가 아닌 개체 수를 반환합니다 ." 따라서 예제 코드는 작성된대로 정확합니다.
new String(new []{'\uD800', '\u0030'})
Globalization.SortKey
, 추출 KeyData
(A) 내로 각각의 행 및 팩 생성 바이트 String
[문자 당 2 바이트 MSB 먼저 , 호출 String.CompareOrdinal
결과 스트링에 것은 전화보다 훨씬 빠르다 SortKey.Compare
의 인스턴스 SortKey
또는 심지어 memcmp
그 인스턴스를 호출 합니다. 내가 왜 궁금 점을 감안 KeyData
반환 Byte[]
보다는를 String
?
귀하의 질문의 첫 번째 부분 (바이트를 얻는 방법)은 이미 다른 사람들에 의해 답변되었습니다 : System.Text.Encoding
네임 스페이스를보십시오.
다음 질문에 답하겠습니다. 왜 인코딩을 선택해야합니까? 왜 문자열 클래스 자체에서 얻을 수 없습니까?
답은 두 부분으로되어 있습니다.
우선, 문자열 클래스 가 내부적으로 사용하는 바이트 는 중요하지 않으며 ,이를 가정 할 때마다 버그가 발생할 수 있습니다.
프로그램이 전적으로 .Net 세계에있는 경우 네트워크를 통해 데이터를 전송하더라도 문자열에 대한 바이트 배열을 얻는 것에 대해 걱정할 필요가 없습니다. 대신 .Net Serialization을 사용하여 데이터 전송에 대해 걱정하십시오. 더 이상 실제 바이트에 대해 걱정하지 않아도됩니다. Serialization 포맷터가이를 대신합니다.
반면에, 당신이 보장 할 수없는 어딘가에이 바이트를 보내면 .Net 직렬 스트림에서 데이터를 가져올 것입니까? 이 경우 분명히 외부 시스템이 관심을 갖기 때문에 인코딩에 대해 걱정할 필요가 있습니다. 다시 말하지만 문자열에 사용되는 내부 바이트는 중요하지 않습니다. 인코딩을 선택해야 .Net에서 내부적으로 사용하는 것과 동일한 인코딩이라도 수신 측에서이 인코딩에 대해 명시 적으로 지정할 수 있습니다.
이 경우 가능한 경우 메모리에 문자열 변수로 저장된 실제 바이트를 바이트 스트림을 만드는 일부 작업을 저장할 수 있다는 아이디어와 함께 사용하는 것이 좋습니다. 그러나 출력을 다른 쪽 끝에서 이해하고 인코딩으로 명시 적으로 보장 해야하는 것과 비교하여 중요하지 않습니다 . 또한 내부 바이트와 실제로 일치 시키려면 이미 Unicode
인코딩을 선택하고 성능을 향상시킬 수 있습니다.
어느 따기 ... 두 번째 부분에 저를 가져다 Unicode
인코딩 되는 기본 바이트를 사용하는 닷넷 이야기. 새로운 인코딩 된 Unicode-Plus가 나올 때 .Net 런타임은 프로그램을 중단하지 않고이 새롭고 더 나은 인코딩 모델을 자유롭게 사용할 수 있어야하므로이 인코딩을 선택해야합니다. 그러나 당분간 (그리고 미래에도) 유니 코드 인코딩을 선택하면 원하는 것을 얻을 수 있습니다.
또한 문자열을 와이어로 다시 작성해야한다는 것을 이해하는 것이 중요 하며 일치하는 인코딩을 사용하는 경우에도 비트 패턴을 적어도 일부 변환 해야합니다 . 컴퓨터는 Big vs Little Endian, 네트워크 바이트 순서, 패킷 화, 세션 정보 등을 고려해야합니다.
그냥 Mehrdrad의 사운드 함을 입증하기에 응답 작품, 그의 접근조차 유지할 수 있습니다 짝 대리 문자 많은 내 대답에 대해 수평 있던를 (하지만있는 모든 사람들이 예를 들어, 똑같이 유죄 System.Text.Encoding.UTF8.GetBytes
, System.Text.Encoding.Unicode.GetBytes
, 그 인코딩 방법은 높은 대리를 지속 할 수없는 d800
예를 들어 문자 는 단순히 대리 문자를 value로 대체합니다. 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);
}
}
산출:
T 54
e 65
s 73
t 74
? d800
T 54
e 65
s 73
t 74
함께 것을 시도 System.Text.Encoding.UTF8.GetBytes 또는 System.Text.Encoding.Unicode.GetBytes , 그들은 단지 가치 높은 대리 문자를 대체합니다 FFFD를
이 질문에 움직임이있을 때마다 여전히 짝을 이루지 않은 대리 문자가 포함 된 문자열을 유지할 수있는 직렬 변환기 (Microsoft 또는 타사 구성 요소의 경우)를 생각하고 있습니다. 나는 이것을 매번 구글로 보낸 다음 : serialization unpaired surrogate character .NET . 이것은 내가 잠을 잃지 않게하지만, 매번 그런 다음 누군가 내 대답에 결함이 있다고 언급하면서 성가시다. 그러나 짝을 이루지 않은 대리 문자에 관해서는 그들의 답변에 똑같이 결함이있다.
이놈, 마이크로 소프트는 사용 했어야 System.Buffer.BlockCopy
의에 BinaryFormatter
ツ
谢谢!
System.Buffer.BlockCopy
내부적으로 사용하는 직렬화 라이브러리가 있다면 , 모든 인코딩 옹호론자들의 주장은 불분명 할 것입니다
FFFD
해당 문자에 오류가 발생 합니다. 수동 문자열 조작을 수행하려면 권장되는대로 char []를 사용하십시오.
System.String
는 불변 시퀀스이며 Char
; .NET은 원본 에 짝을 이루지 않은 서로 게이트가 포함되어 있어도 String
개체를 항상 구성 하여 동일한 값을 포함하는 Char[]
내용으로 내 보냅니다 . Char[]
Char[]
훨씬 적은 코드로 이것을 시도하십시오.
System.Text.Encoding.UTF8.GetBytes("TEST String");
System.Text.Encoding.UTF8.GetBytes("Árvíztűrő tükörfúrógép);
하고 울으십시오! 그것은 작동하지만 것 System.Text.Encoding.UTF8.GetBytes("Árvíztűrő tükörfúrógép").Length != System.Text.Encoding.UTF8.GetBytes("Arvizturo tukorfurogep").Length
동안"Árvíztűrő tükörfúrógép".Length == "Arvizturo tukorfurogep".Length
글쎄, 나는 모든 대답을 읽었으며 그들은 짝을 이루지 않은 대리자를 버리는 인코딩 또는 직렬화에 관한 것입니다.
예를 들어, 문자열 이 암호 해시와 같은 바이트 배열을 저장하는 SQL Server 에서 가져온 경우에는 좋지 않습니다 . 우리가 그것으로부터 무엇인가를 버린다면, 그것은 유효하지 않은 해시를 저장할 것이고, 우리가 그것을 XML로 저장하기를 원한다면, 우리는 그것을 XML 그대로 남겨두기를 원합니다.
따라서 이러한 경우 바이트 배열의 Base64 인코딩을 사용 하지만 인터넷에는 C #에 대한 해결책이 하나 뿐이며 버그가 있으며 한 가지 방법이므로 버그를 수정하고 다시 작성했습니다. 순서. 미래의 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);
}
Convert.ToBase64String(arr);
base64 변환에는 사용 했습니다 byte[] (data) <-> string (serialized data to store in XML file)
. 그러나 초기를 얻으려면 바이너리 데이터 가 포함 된 byte[] (data)
무언가를 수행해야 했습니다 (MSSQL이 나에게 그것을 반환 한 방식입니다). 따라서 위의 기능은입니다 . String
String (binary data) <-> byte[] (easy accessible binary data)
또한 인코딩을 고려해야하는 이유도 설명하십시오. 문자열이 저장된 바이트를 간단히 얻을 수 없습니까? 왜 인코딩에 의존 하는가? !!!
"문자열의 바이트"와 같은 것은 없기 때문입니다.
문자열 (또는 일반적으로 텍스트)은 문자, 숫자 및 기타 기호로 구성됩니다. 그게 다야. 그러나 컴퓨터는 캐릭터에 대해 아무것도 모릅니다. 바이트 만 처리 할 수 있습니다. 따라서 컴퓨터를 사용하여 텍스트를 저장하거나 전송하려면 문자를 바이트로 변환해야합니다. 어떻게합니까? 여기에 인코딩이 나오는 곳이 있습니다.
인코딩은 논리 문자를 물리 바이트로 변환하는 규칙 일뿐입니다. 가장 간단하고 잘 알려진 인코딩은 ASCII이며 영어로 작성하는 경우 필요한 모든 것입니다. 다른 언어의 경우 오늘날 가장 안전한 선택 인 유니 코드의 풍미 인보다 완전한 인코딩이 필요합니다.
즉, "인코딩을 사용하지 않고 문자열의 바이트를 얻는"것은 "언어를 사용하지 않고 텍스트를 작성"하는 것만 큼 불가능합니다.
그건 그렇고, 나는 당신과 그 문제에 대해이 작은 지혜를 읽을 것을 강력히 권장합니다 . 절대적으로 모든 소프트웨어 개발자는 절대적으로 유니 코드와 문자 세트에 대해 알아야합니다 (변명 없음!)
byte[] strToByteArray(string str)
{
System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
return enc.GetBytes(str);
}
문자열과 바이트 배열 간의 변환에 다음 코드를 사용할 수 있습니다.
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);
의 출현 Span<T>
C # 7.2 출시 정규 기술이다 관리 바이트 배열에 캐릭터의 기본 메모리 표현을 캡처 :
byte[] bytes = "rubbish_\u9999_string".AsSpan().AsBytes().ToArray();
데이터를 다시 변환하는 것은 스타터가 아닌 것이되어야합니다. 왜냐하면 데이터를 어떻게 든 해석하고 있지만 완전성을 위해서이기 때문입니다.
string s;
unsafe
{
fixed (char* f = &bytes.AsSpan().NonPortableCast<byte, char>().DangerousGetPinnableReference())
{
s = new string(f);
}
}
이름 NonPortableCast
과 DangerousGetPinnableReference
당신이 아마 이것을해서는 안된다는 주장을 더해야합니다.
작업 Span<T>
하려면 System.Memory NuGet 패키지를 설치해야 합니다 .
에 관계없이 실제 원래의 질문과 의견을 후속는 기본 메모리가 나타내는 (I 수정 또는있는 그대로를 작성할 필요 이상으로 읽을 수 없습니다되는 수단을 가정한다) "해석"되지 않는 것을 의미 그 일부 구현 Stream
클래스 데이터를 문자열로 추론하는 대신 사용해야합니다.
확실하지 않지만 문자열은 정보를 Chars의 배열로 저장한다고 생각합니다. 바이트는 비효율적입니다. 특히 Char의 정의는 "Unicode 문자를 나타냅니다"입니다.
이 예제 샘플을 보자.
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));
}
유니 코드 응답은 두 경우 모두 14 바이트 인 반면 UTF-8 응답은 첫 번째는 9 바이트이고 두 번째는 7 바이트입니다.
따라서 문자열이 사용하는 바이트를 원하면을 사용 Encoding.Unicode
하면되지만 저장 공간이 비효율적입니다.
주요 문제는 문자열의 글리프가 32 비트 (문자 코드의 경우 16 비트)를 사용하지만 한 바이트에는 8 비트 만 남겨야한다는 것입니다. ASCII 문자 만 포함 된 문자열로 제한하지 않으면 일대일 매핑이 존재하지 않습니다. System.Text.Encoding에는 문자열을 byte []에 매핑하는 방법이 많이 있습니다. 정보 손실을 피하고 byte []를 다시 문자열에 매핑해야 할 때 클라이언트가 쉽게 사용할 수있는 방법을 선택해야합니다. .
Utf8은 널리 사용되는 인코딩이며 크기가 작고 손실이 없습니다.
가장 빠른 방법
public static byte[] GetBytes(string text)
{
return System.Text.ASCIIEncoding.UTF8.GetBytes(text);
}
편집 Makotosan 등이 지금 최선의 방법입니다 주석 :
Encoding.UTF8.GetBytes(text)
특정 인코딩을 수동으로 지정하지 않고 .NET (C #)에서 문자열을 바이트 []로 어떻게 변환합니까?
.NET 의 문자열 은 텍스트를 UTF-16 코드 단위의 시퀀스로 나타내므로 바이트는 이미 UTF-16의 메모리에 인코딩됩니다.
Mehrdad의 답변
당신이 사용할 수있는 Mehrdad의 답변을 있지만 문자는 UTF-16이므로 실제로 인코딩을 사용합니다. 그것은보고 ToCharArray 호출 소스 것은 만들어 char[]
직접에 복사 메모리를. 그런 다음 할당 된 바이트 배열에 데이터를 복사합니다. 따라서 후드 아래에서 기본 바이트를 두 번 복사 하고 호출 후에 사용되지 않는 char 배열을 할당합니다.
Tom Blodget의 답변
Tom Blodget의 대답 은 Mehrdad보다 20-30 % 빠릅니다. 문자 배열을 할당하고 바이트를 복사하는 중간 단계를 건너 뛰기 때문에 /unsafe
옵션으로 컴파일해야합니다 . 인코딩을 절대 사용하고 싶지 않다면 이것이 방법이라고 생각합니다. 암호화 로그인을 fixed
블록 안에 넣으면 별도의 바이트 배열을 할당하고 바이트를 복사 할 필요가 없습니다.
또한 인코딩을 고려해야하는 이유는 무엇입니까? 문자열이 저장된 바이트를 간단히 얻을 수 없습니까? 문자 인코딩에 의존하는 이유는 무엇입니까?
그것이 올바른 방법이기 때문입니다. string
추상화입니다.
유효하지 않은 문자가있는 '문자열'이있는 경우 인코딩을 사용하면 문제가 발생할 수 있지만 그렇게되지 않아야합니다. 유효하지 않은 문자로 문자열로 데이터를 가져 오는 경우 잘못하고 있습니다. 아마도 바이트 배열이나 Base64 인코딩을 사용해야 할 것입니다.
를 사용 System.Text.Encoding.Unicode
하면 코드가 더 탄력적입니다. 엔디안 에 대해 걱정할 필요가 없습니다.코드가 실행될 시스템 에 . 다음 버전의 CLR에서 다른 내부 문자 인코딩을 사용할지 걱정할 필요가 없습니다.
나는 질문이 인코딩에 대해 걱정하고 싶은 이유가 아니라 그것을 무시하고 다른 것을 사용하려는 이유라고 생각합니다. 인코딩은 일련의 바이트로 문자열의 추상화를 나타냅니다. System.Text.Encoding.Unicode
약간의 엔디 언 바이트 순서 인코딩을 제공하며 현재와 미래의 모든 시스템에서 동일하게 수행됩니다.
OP의 질문에 가장 가까운 접근 방식은 Tom Blodget입니다. 이는 실제로 객체로 들어가서 바이트를 추출합니다. String Object의 구현에 달려 있기 때문에 가장 가깝습니다.
"Can't I simply get what bytes the string has been stored in?"
물론, 그것이 문제의 근본적인 오류가 발생하는 곳입니다. 문자열은 흥미로운 데이터 구조를 가질 수있는 객체입니다. 페어링되지 않은 대리자를 저장할 수 있기 때문에 이미 알고 있습니다. 길이를 저장할 수 있습니다. 빠른 '계산'을 허용하는 각각의 '페어링 된'서로 게이트에 대한 포인터를 유지할 수 있습니다. 기타이 여분의 바이트는 모두 문자 데이터의 일부가 아닙니다.
원하는 것은 배열의 각 문자 바이트입니다. 그리고 그것은 '인코딩'이 들어오는 곳입니다. 기본적으로 UTF-16LE를 얻게됩니다. 왕복을 제외하고 바이트 자체에 신경 쓰지 않으면 'default'를 포함하여 인코딩을 선택하고 나중에 다시 변환 할 수 있습니다 (기본 인코딩과 같은 동일한 매개 변수, 코드 포인트, 버그 수정 가정) , 짝을 이루지 않은 대리모 등과 같은 허용되는 것들
그러나 왜 '인코딩'을 마술로 남겨 두어야합니까? 어떤 바이트를 얻을지 알 수 있도록 인코딩을 지정하지 않겠습니까?
"Why is there a dependency on character encodings?"
인코딩 (이 문맥에서)은 단순히 문자열을 나타내는 바이트를 의미합니다. 문자열 객체의 바이트가 아닙니다. 문자열이 저장된 바이트를 원했습니다. 이것은 질문이 순진하게 요청 된 곳입니다. 문자열 객체를 포함 할 수있는 다른 모든 이진 데이터가 아니라 문자열을 나타내는 연속 배열에 문자열 바이트를 원했습니다.
이는 문자열이 저장되는 방식과 관련이 없음을 의미합니다. 바이트 배열에서 바이트로 "인코딩 된"문자열을 원합니다.
Tom Bloget의 대답이 마음에 들었습니다. '바이트 단위의 문자열 객체'방향으로 안내했기 때문입니다. 그러나 구현에 따라 다르며 내부에서 엿보기 때문에 문자열 사본을 재구성하기가 어려울 수 있습니다.
Mehrdad의 반응은 개념적 수준에서 오도하기 때문에 잘못되었습니다. 여전히 인코딩 된 바이트 목록이 있습니다. 그의 특정 솔루션은 짝을 이루지 않은 대리자를 보존 할 수있게합니다. 이는 구현에 따라 다릅니다. 그의 특정 솔루션은 GetBytes
기본적으로 문자열을 UTF-8로 반환하면 문자열 의 바이트를 정확하게 생성하지 않습니다 .
나는 이것에 대해 마음을 바꿨다 (Mehrdad의 해결책). 이것은 문자열의 바이트를 얻지 못한다. 오히려 문자열에서 작성된 문자 배열의 바이트를 가져옵니다. 인코딩에 관계없이 c #의 char 데이터 형식은 고정 크기입니다. 이를 통해 일관된 길이의 바이트 배열을 생성 할 수 있으며 바이트 배열의 크기에 따라 문자 배열을 재생할 수 있습니다. 따라서 인코딩이 UTF-8이지만 각 문자가 최대 utf8 값을 수용하기 위해 6 바이트 인 경우에도 여전히 작동합니다. 실제로 캐릭터의 인코딩은 중요하지 않습니다.
그러나 변환이 사용되었습니다. 각 문자는 고정 크기 상자 (c #의 문자 유형)에 배치되었습니다. 그러나 그 표현이 중요하지 않은 것은 기술적으로 OP에 대한 해답입니다. 그래서-만약 당신이 어쨌든 변환하려고한다면 ... 왜 '인코딩'하지?
(Char) 55906
(Char) 55655
문자열의 기본 바이트 사본을 실제로 원한다면 다음과 같은 함수를 사용할 수 있습니다. 그러나 이유를 찾기 위해 계속 읽어서 는 안됩니다 .
[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;
}
이 함수는 문자열의 기초가되는 바이트의 복사본을 매우 빠르게 가져옵니다. 시스템에서 인코딩하는 방식에 관계없이 해당 바이트를 가져옵니다. 이 인코딩은 거의 확실히 UTF-16LE이지만 걱정할 필요가없는 구현 세부 사항입니다.
전화하는 것이 더 안전하고 간단하며 안정적입니다 .
System.Text.Encoding.Unicode.GetBytes()
우연히도 동일한 결과를 제공하고 입력하기가 쉽고 바이트는 항상 호출로 왕복합니다.
System.Text.Encoding.Unicode.GetString()
여기 내 안전하지 않은 구현 String
으로 Byte[]
변환 :
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;
}
비록 우아하지는 않지만 허용되는 답변자의 것보다 훨씬 빠릅니다. 10000000 회 이상의 스톱워치 벤치 마크는 다음과 같습니다.
[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
이를 사용하려면 프로젝트 빌드 속성에서 "안전하지 않은 코드 허용"을 선택해야합니다. .NET Framework 3.5에 따라이 방법은 문자열 확장으로도 사용할 수 있습니다.
public static unsafe class StringExtensions
{
public static Byte[] ToByteArray(this String s)
{
// Method Code
}
}
RuntimeHelpers.OffsetToStringData
.NET의 아이테니엄 버전 8의 배수는? 그렇지 않으면 정렬되지 않은 읽기로 인해 실패합니다.
memcpy
않습니까? stackoverflow.com/a/27124232/659190
간단히 이것을 사용하십시오 :
byte[] myByte= System.Text.ASCIIEncoding.Default.GetBytes(myString);
System.Text.ASCIIEncoding.Default.GetBytes("Árvíztűrő tükörfúrógép.").ToString();
을 반환 "Árvizturo tukörfurogép."
합니다. (그리고 나는 당신이 모든 문자를 풀어 놓을 아시아 언어에 대해서는 언급하지 않았습니다.)
문자열은 다음과 같은 사실 때문에 몇 가지 다른 방식으로 바이트 배열로 변환 될 수 있습니다. .NET은 유니 코드를 지원하고 유니 코드는 UTF라고하는 몇 가지 차이 인코딩을 표준화합니다. 바이트 길이는 다르지만 문자열을 인코딩 할 때 문자열로 다시 코드화 할 수 있지만 문자열이 하나의 UTF로 인코딩되고 다른 UTF를 가정하여 고정 될 수있는 경우 문자열로 인코딩 될 수 있다는 점에서 동일합니다. 쪽으로.
또한 .NET은 비 유니 코드 인코딩을 지원하지만 일반적인 경우에는 유효하지 않습니다 (유니 코드 코드 포인트의 제한된 하위 집합이 ASCII와 같은 실제 문자열에 사용되는 경우에만 유효 함). 내부적으로 .NET은 UTF-16을 지원하지만 스트림 표현에는 일반적으로 UTF-8이 사용됩니다. 또한 인터넷의 표준이기도합니다.
당연히 문자열을 바이트 배열로 직렬화 및 역 직렬화는 System.Text.Encoding
추상 클래스 인 클래스 에서 지원됩니다 . 파생 클래스는 구체적인 인코딩을 지원합니다. ASCIIEncoding
4 개의 System.Text.UnicodeEncoding
UTF ( UTF-16 지원)
를 사용하여 바이트 배열로 직렬화합니다 System.Text.Encoding.GetBytes
. 역 연산의 경우 System.Text.Encoding.GetChars
. 이 함수는 문자 배열을 반환하므로 문자열을 얻으려면 문자열 생성자를 사용하십시오 System.String(char[])
.
이 페이지를 참조하십시오.
예:
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? :-)
타일러가 적절하게 말했듯 이 "문자열은 순수한 데이터가 아니며 정보 도 가지고 있습니다 ." 이 경우 정보는 문자열이 작성 될 때 가정 된 인코딩입니다.
이것은 자신의 질문에 대한 OP의 의견을 기반으로하며 유스 케이스에서 OP의 힌트를 이해하면 올바른 질문입니다.
이진 데이터를 문자열로 저장하는 것은 위에서 언급 한 가정 된 인코딩으로 인해 잘못된 접근법 일 것입니다! 이진 데이터를 string
( byte[]
적절한 배열 대신에) 저장 한 프로그램이나 라이브러리 는 이미 시작하기 전에 이미 패배했습니다. REST 요청 / 응답 또는 문자열을 전송 해야하는 모든 것에서 바이트를 전송하는 경우 Base64 가 올바른 방법입니다.
다른 사람들은이 잘못된 질문에 잘못 대답했습니다.
문자열이 그대로 좋아 보인다면 인코딩 (바람직하게는 UTF로 시작하는 인코딩)을 선택하고 해당 System.Text.Encoding.???.GetBytes()
기능을 사용하고 선택한 인코딩을 바이트에 제공하는 사람에게 알려주십시오.
바이트로 무엇을 하려는지 묻는 질문에 다음과 같이 응답했습니다 .
암호화하겠습니다. 변환하지 않고 암호화 할 수는 있지만 여전히 인코딩이 왜 여기에서 이루어지는 지 알고 싶습니다. 나에게 바이트를 알려주십시오.
이 암호화 된 데이터를 네트워크를 통해 보내거나 나중에 메모리에 다시로드하거나 다른 프로세스로 스팀을 보내든 관계 없이 어느 시점에서 분명히 해독 하려고합니다 . 그 경우에, 당신은 통신 프로토콜을 정의하고 있다는 것입니다. 통신 프로토콜은 프로그래밍 언어 및 관련 런타임의 구현 세부 사항 측면에서 정의 되어서는 안됩니다 . 이에 대한 몇 가지 이유가 있습니다.
의사 소통을하려면 (완전히 다른 프로세스 또는 향후 동일한 프로그램과) 프로토콜을 사용하여 작업하기가 어렵거나 실수로 버그가 발생하는 것을 최소화하기 위해 프로토콜을 엄격하게 정의해야합니다 . .NET의 내부 표현에 따라 엄격하고 명확하거나 일관된 정의가 보장되는 것은 아닙니다. 표준 인코딩 은 앞으로도 실패하지 않을 엄격한 정의입니다.
즉, 인코딩을 지정하지 않으면 일관성 요구 사항을 충족시킬 수 없습니다 .
당신은 할 수 확실히 당신이 찾아내는 경우 직접 UTF-16을 사용하도록 선택하는 프로세스가 수행하는 훨씬 더 나은 .NET 내부적으로 또는 다른 이유로 그것을 사용하지만, 명시 적으로 인코딩하는 것을 선택하고 따라보다 코드에서 명시 적으로 이러한 변환을 대신 수행 할 필요가 있기 때문에 .NET의 내부 구현.
따라서 인코딩을 선택하고 사용하십시오.
using System.Text;
// ...
Encoding.Unicode.GetBytes("abc"); # UTF-16 little endian
Encoding.UTF8.GetBytes("abc")
보다시피, 내장 된 인코딩 객체를 사용하는 독자적인 리더 / 라이터 메소드를 구현하는 것보다 실제로 코드가 적습니다.
두 가지 방법:
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();
}
과,
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;
}
나는 바닥보다 더 자주 바닥을 사용하는 경향이 있으며 속도를 벤치마킹하지 않았습니다.
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