etc./StackOverFlow

인코딩을 수동으로 지정하지 않고 C#에서 문자열의 일관된 바이트 표현을 얻으려면 어떻게 해야 합니까?

청렴결백한 만능 재주꾼 2021. 11. 26. 06:55
반응형

질문자 :Agnel Kurian


특정 인코딩을 수동으로 지정하지 않고 .NET(C#)에서 stringbyte[] 로 어떻게 변환합니까?

문자열을 암호화하겠습니다. 변환하지 않고 암호화할 수 있지만 여기에서 인코딩이 재생되는 이유를 알고 싶습니다.

또한 인코딩을 고려해야 하는 이유는 무엇입니까? 문자열이 저장된 바이트를 간단히 가져올 수 없습니까? 문자 인코딩에 대한 종속성이 있는 이유는 무엇입니까?



여기에 있는 답변과 달리 바이트를 해석할 필요가 없는 경우 인코딩에 대해 걱정할 필요가 없습니다!

언급했듯이 목표는 단순히 "문자열이 저장된 바이트를 가져오는 것" 입니다.
(물론 바이트에서 문자열을 재구성할 수 있습니다.)

이러한 목표를 위해 사람들이 왜 인코딩이 필요하다고 계속 말하는지 솔직히 이해가 되지 않습니다. 당신은 확실히 이것에 대한 인코딩에 대해 걱정할 필요가 없습니다.

대신 다음을 수행하십시오.

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

당신의 프로그램(또는 다른 프로그램)이 바이트를 해석 하려고 하지 않는 한, 당신이 의도한 바를 분명히 언급하지 않았다면, 이 접근 방식 에는 아무런 문제가 없습니다! 인코딩에 대해 걱정하면 진짜 이유 없이 삶이 더 복잡해집니다.

이 접근 방식의 추가 이점: 문자열에 잘못된 문자가 포함되어 있어도 문제가 되지 않습니다. 어쨌든 데이터를 가져오고 원래 문자열을 재구성할 수 있기 때문입니다!

바이트열을 보고 있기 때문에 인코딩 및 디코딩이 동일합니다.

하지만 특정 인코딩을 사용했다면 잘못된 문자를 인코딩/디코딩하는 데 문제가 생겼을 것입니다.


user541686

문자열 인코딩( 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)의 문자 인코딩을 참조하세요.


bmotmans

허용되는 답변은 매우 매우 복잡합니다. 이를 위해 포함된 .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);

필요하지 않다면 바퀴를 재발명하지 마세요...


Erik A. Brandstadmoen

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

Michael Buen

1개의 문자는 1개 이상의 바이트(최대 약 6개)로 표현될 수 있고 다른 인코딩은 이러한 바이트를 다르게 처리하기 때문에 인코딩을 고려해야 합니다.

Joel은 이에 대한 게시물을 가지고 있습니다.

모든 소프트웨어 개발자는 유니코드 및 문자 집합에 대해 절대적으로, 긍정적으로 알아야 하는 절대 최소값(변명의 여지가 없습니다!)


Zhaph - Ben Duguid

이것은 인기 있는 질문입니다. 질문 작성자가 무엇을 묻는지, 그리고 그것이 가장 일반적인 요구 사항과 다른지 이해하는 것이 중요합니다. 필요하지 않은 코드의 오용을 방지하기 위해 나중에 먼저 답변했습니다.

공통 요구 사항

모든 문자열에는 문자 집합과 인코딩이 있습니다. 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 배열을 Byte 배열로 변환하는 방법을 보여줍니다. 그러나 이것은 문자열을 두 번 복사합니다! System.Char 데이터 유형을 명시적으로 사용합니다.

String이 저장된 실제 바이트를 얻는 유일한 방법은 포인터를 사용하는 것입니다. fixed 문은 값의 주소를 가져오는 것을 허용합니다. C# 사양에서:

[For] 유형 문자열의 표현식, ... 이니셜라이저는 문자열의 첫 번째 문자 주소를 계산합니다.

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가 지적했듯이 결과는 기계의 엔디안성에 따라 다릅니다. 그러나 질문 작성자는 그것에 대해 걱정하지 않습니다.


Tom Blodget

질문의 첫 번째 부분(바이트를 얻는 방법)은 이미 다른 사람들이 답변했습니다 System.Text.Encoding 네임스페이스를 살펴보세요.

다음 질문에 답하겠습니다. 인코딩을 선택해야 하는 이유는 무엇입니까? 왜 문자열 클래스 자체에서 그것을 얻을 수 없습니까?

답은 두 부분으로 나뉩니다.

우선, string 클래스에서 내부적으로 사용하는 바이트 는 중요하지 않으며 , 그렇게 가정할 때마다 버그를 도입할 가능성이 높습니다.

프로그램이 완전히 .Net 세계 안에 있다면 네트워크를 통해 데이터를 전송하더라도 문자열에 대한 바이트 배열을 얻는 것에 대해 전혀 걱정할 필요가 없습니다. 대신 .Net 직렬화를 사용하여 데이터 전송에 대해 걱정하십시오. 더 이상 실제 바이트에 대해 걱정하지 않아도 됩니다. 직렬화 포맷터가 알아서 해줍니다.

반면에 .Net 직렬화된 스트림에서 데이터를 가져올 것이라고 보장할 수 없는 어딘가에 이러한 바이트를 보낸다면 어떻게 될까요? 이 경우 분명히 인코딩에 대해 걱정할 필요가 있습니다. 분명히 이 외부 시스템이 신경을 쓰기 때문입니다. 다시 말하지만, 문자열에서 사용하는 내부 바이트는 중요하지 않습니다. 인코딩을 선택해야 .Net에서 내부적으로 사용하는 인코딩과 동일하더라도 수신 측에서 이 인코딩에 대해 명시할 수 있습니다.

이 경우 바이트 스트림을 생성하는 작업을 절약할 수 있다는 생각으로 가능한 경우 메모리의 문자열 변수에 의해 저장된 실제 바이트를 사용하는 것을 선호할 수 있음을 이해합니다. 그러나 다른 쪽에서 출력을 이해하고 인코딩을 명시적으로 해야 함을 보장하는 것과 비교하면 중요하지 않습니다. 또한 내부 바이트를 일치시키려면 이미 Unicode 인코딩을 선택하고 성능을 절약할 수 있습니다.

두 번째 부분으로 이동합니다. Unicode 인코딩을 선택하는 것은 .Net에 기본 바이트를 사용하도록 지시하는 것입니다. 이 인코딩을 선택해야 합니다. 새로운 유니코드 플러스가 나올 때 .Net 런타임은 프로그램을 중단하지 않고 이 새롭고 더 나은 인코딩 모델을 자유롭게 사용할 수 있어야 하기 때문입니다. 그러나 현재로서는(그리고 가까운 미래에도) 유니코드 인코딩을 선택하는 것만으로도 원하는 것을 얻을 수 있습니다.

문자열을 와이어로 다시 작성해야 하며 일치하는 인코딩을 사용하는 경우에도 비트 패턴의 적어도 일부 변환이 포함된다는 것을 이해하는 것도 중요합니다. 컴퓨터는 Big vs Little Endian, 네트워크 바이트 순서, 패킷화, 세션 정보 등을 고려해야 합니다.


Joel Coehoorn

Mehrdrad의 건전한 답변이 효과가 있음을 보여주기 위해 그의 접근 방식은 짝을 이루지 않은 대리 문자를 유지할 수도 있습니다(많은 사람들이 내 답변에 대해 평준화했지만 모든 사람이 똑같이 유죄입니다(예: System.Text.Encoding.UTF8.GetBytes , System.Text.Encoding.Unicode.GetBytes , 그 부호화 방법은 높은 대리 캐릭터 유지할 수 d800 예를 들어, 그 그냥 단지 값 높은 게이트 문자 대체 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 또는 타사 구성 요소)를 여전히 생각하고 있습니다. 나는 이것을 가끔 구글링한다: 직렬화 짝이 없는 대리 문자 .NET . 이것은 내가 잠을 잘 자지 못하게 하지만 때때로 누군가가 내 대답에 결함이 있다고 논평할 때 일종의 성가신 일이지만, 짝을 이루지 않은 대리 캐릭터에 관해서도 그들의 대답은 똑같이 결함이 있습니다.

Darn, Microsoft는 BinaryFormatter System.Buffer.BlockCopy 를 사용했어야 했습니다.

谢谢!


Community Wiki

훨씬 적은 코드로 이것을 시도하십시오.

 System.Text.Encoding.UTF8.GetBytes("TEST String");

Nathan

글쎄, 나는 모든 답변을 읽었으며 인코딩을 사용하거나 짝을 이루지 않은 대리를 삭제하는 직렬화에 대한 답변을 읽었습니다.

예를 들어 문자열이 예를 들어 암호 해시를 저장하는 바이트 배열에서 구축된 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); }

Gman

또한 인코딩을 고려해야 하는 이유를 설명해 주십시오. 문자열이 저장된 바이트를 간단히 가져올 수 없습니까? 왜 인코딩에 대한 의존성이 있습니까? !!!

"문자열의 바이트"와 같은 것이 없기 때문입니다.

문자열(또는 더 일반적으로 텍스트)은 문자, 숫자 및 기타 기호와 같은 문자로 구성됩니다. 그게 다야. 그러나 컴퓨터는 문자에 대해 아무것도 모릅니다. 바이트만 처리할 수 있습니다. 따라서 컴퓨터를 사용하여 텍스트를 저장하거나 전송하려면 문자를 바이트로 변환해야 합니다. 어떻게 합니까? 여기에서 인코딩이 장면에 적용됩니다.

인코딩은 논리적 문자를 물리적 바이트로 변환하는 규칙에 불과합니다. 가장 간단하고 가장 잘 알려진 인코딩은 ASCII이며 영어로 작성하는 경우 필요한 모든 것입니다. 다른 언어의 경우 더 완전한 인코딩이 필요하며 오늘날 가장 안전한 선택이 되는 유니코드 맛입니다.

따라서 간단히 말해서 "인코딩을 사용하지 않고 문자열의 바이트를 가져오는" 시도는 "어떠한 언어도 사용하지 않고 텍스트를 작성하는 것"만큼 불가능합니다.

그건 그렇고, 나는 당신(그리고 그 문제에 대해 누구에게나)이 이 작은 지혜를 읽을 것을 강력히 추천합니다: 절대 최소 모든 소프트웨어 개발자는 유니코드와 문자 집합에 대해 절대적으로, 긍정적으로 알아야 합니다(변명의 여지가 없습니다!)


Konamiman

stringbyte 배열로 변환하는 C#:

 public static byte[] StrToByteArray(string str) { System.Text.UTF8Encoding encoding=new System.Text.UTF8Encoding(); return encoding.GetBytes(str); }

Shyam sundar shah

byte[] strToByteArray(string str) { System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); return enc.GetBytes(str); }

gkrogers

문자열과 바이트 배열 간의 변환을 위해 다음 코드를 사용할 수 있습니다.

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

Jarvis Stark

Span<T> 의 출현으로 문자열의 기본 메모리 표현을 관리되는 바이트 배열로 캡처하는 표준 기술은 다음과 같습니다.

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

다시 변환하는 것은 시작이 아니어야 합니다. 즉, 실제로 데이터를 어떻게든 해석하지만 완전성을 위해 다음과 같이 하기 때문입니다.

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

NonPortableCastDangerousGetPinnableReference 라는 이름은 아마도 이렇게 해서는 안 된다는 주장을 더욱 강화해야 합니다.

Span<T> 하려면 System.Memory NuGet 패키지를 설치해야 합니다.

그럼에도 불구하고 실제 원래 질문과 후속 의견은 기본 메모리가 "해석"되지 않고 있음을 의미하며(이는 그대로 쓸 필요 이상으로 수정되거나 읽히지 않는다고 가정함) Stream 데이터를 문자열로 전혀 추론하는 대신 클래스를 사용해야 합니다.


John Rasch

확실하지 않지만 문자열이 정보를 Chars 배열로 저장한다고 생각합니다. 이는 바이트에서 비효율적입니다. 특히 Char의 정의는 "유니코드 문자를 나타냄"입니다.

이 예제 샘플을 사용하십시오.

 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 를 사용하면 되지만 저장 공간이 비효율적입니다.


Ed Marty

핵심 문제는 문자열의 글리프가 32비트(문자 코드의 경우 16비트)를 차지하지만 바이트에는 8비트만 남는다는 것입니다. ASCII 문자만 포함하는 문자열로 제한하지 않는 한 일대일 매핑은 존재하지 않습니다. System.Text.Encoding에는 문자열을 byte[]에 매핑하는 방법이 많이 있습니다. 정보 손실을 방지하고 클라이언트가 byte[]를 문자열에 다시 매핑해야 할 때 사용하기 쉬운 방법을 선택해야 합니다. .

Utf8은 널리 사용되는 인코딩으로 압축되어 손실이 없습니다.


Hans Passant

사용하다:

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

결과는 다음과 같습니다.

 [0] = 115 [1] = 116 [2] = 114 [3] = 105 [4] = 110 [5] = 103

mashet

가장 빠른 방법

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

Makotosan이 언급한 대로 편집 하는 것이 이제 가장 좋은 방법입니다.

 Encoding.UTF8.GetBytes(text)

Alessandro Annini

OP의 질문에 가장 가까운 접근 방식은 실제로 개체에 들어가서 바이트를 추출하는 Tom Blodget의 것입니다. 나는 그것이 String Object의 구현에 의존하기 때문에 가장 가깝다고 말합니다.

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

물론 문제의 근본적인 오류가 발생합니다. String은 흥미로운 데이터 구조를 가질 수 있는 객체입니다. 페어링되지 않은 서로게이트를 저장할 수 있기 때문에 이미 알고 있습니다. 길이를 저장할 수 있습니다. 빠른 계산을 허용하는 각 '페어링된' 서로게이트에 대한 포인터를 유지할 수 있습니다. 기타 이러한 추가 바이트는 모두 문자 데이터의 일부가 아닙니다.

원하는 것은 배열에 있는 각 문자의 바이트입니다. 그리고 그것이 '인코딩'이 들어오는 곳입니다. 기본적으로 UTF-16LE를 얻을 것입니다. 왕복을 제외하고 바이트 자체에 신경 쓰지 않는다면 '기본'을 포함한 모든 인코딩을 선택하고 나중에 다시 변환할 수 있습니다(기본 인코딩, 코드 포인트, 버그 수정과 같은 동일한 매개변수 가정) , 짝을 이루지 않은 대리자 등과 같이 허용되는 것

그러나 왜 '인코딩'을 마법에 맡겨야 합니까? 얻을 수 있는 바이트를 알 수 있도록 인코딩을 지정하지 않는 이유는 무엇입니까?

 "Why is there a dependency on character encodings?"

인코딩(이 컨텍스트에서)은 단순히 문자열을 나타내는 바이트를 의미합니다. 문자열 개체의 바이트가 아닙니다. 문자열이 저장된 바이트를 원했습니다. 이것이 질문이 순진한 곳입니다. 문자열 개체에 포함될 수 있는 다른 모든 이진 데이터가 아니라 문자열을 나타내는 연속 배열의 문자열 바이트를 원했습니다.

즉, 문자열이 저장되는 방식은 관련이 없습니다. 바이트 배열의 바이트로 "인코딩된" 문자열을 원합니다.

Tom Bloget의 답변이 마음에 듭니다. 왜냐하면 그가 '문자열 개체의 바이트' 방향으로 안내했기 때문입니다. 그러나 구현에 따라 다르며 내부를 엿보고 있기 때문에 문자열 사본을 재구성하는 것이 어려울 수 있습니다.

Mehrdad의 응답은 개념적 수준에서 오해의 소지가 있기 때문에 잘못된 것입니다. 인코딩된 바이트 목록이 여전히 있습니다. 그의 특정 솔루션은 짝을 이루지 않은 서로게이트를 보존할 수 있도록 합니다. 이는 구현에 따라 다릅니다. GetBytes 가 기본적으로 문자열을 UTF-8로 반환한 경우 그의 특정 솔루션은 문자열의 바이트를 정확하게 생성하지 않습니다.


나는 이것에 대해 마음을 바꿨다(Mehrdad의 솔루션) -- 이것은 문자열의 바이트를 얻지 못한다. 오히려 문자열에서 생성된 문자 배열의 바이트를 가져옵니다. 인코딩에 관계없이 C#의 char 데이터 유형은 고정된 크기입니다. 이를 통해 일관된 길이의 바이트 배열을 생성할 수 있으며 바이트 배열의 크기에 따라 문자 배열을 재생할 수 있습니다. 따라서 인코딩이 UTF-8이지만 가장 큰 utf8 값을 수용하기 위해 각 문자가 6바이트라면 여전히 작동합니다. 따라서 실제로 문자의 인코딩은 중요하지 않습니다.

그러나 변환이 사용되었습니다. 각 문자는 고정 크기 상자(c#의 문자 유형)에 배치되었습니다. 그러나 그 표현이 무엇인지는 중요하지 않습니다. 이는 기술적으로 OP에 대한 답변입니다. 그래서 -- 어쨌든 변환하려는 경우 ... '인코딩'하지 않는 이유는 무엇입니까?


Gerard ONeill

특정 인코딩을 수동으로 지정하지 않고 .NET(C#)에서 문자열을 byte[]로 어떻게 변환합니까?

.NET의 문자열 은 텍스트를 일련의 UTF-16 코드 단위로 나타내므로 바이트는 이미 UTF-16으로 메모리에 인코딩되어 있습니다.

메르다드의 대답

Mehrdad의 답변을 사용할 수 있지만 문자가 UTF-16이기 때문에 실제로 인코딩을 사용합니다. 소스 char[] 만들고 메모리를 직접 복사하는 ToCharArray를 호출합니다. 그런 다음 할당된 바이트 배열에 데이터를 복사합니다. 따라서 후드 아래에서는 기본 바이트를 두 번 복사하고 호출 후에 사용되지 않는 char 배열을 할당합니다.

Tom Blodget의 답변

Tom Blodget의 대답 은 char 배열을 할당하고 바이트를 복사하는 중간 단계를 건너뛰기 때문에 Mehrdad보다 20-30% 빠르지만 /unsafe 옵션으로 컴파일해야 합니다. 인코딩을 절대 사용하고 싶지 않다면 이 방법이 맞다고 생각합니다. 암호화 로그인을 fixed 블록 안에 넣으면 별도의 바이트 배열을 할당하고 바이트를 복사할 필요도 없습니다.

또한 인코딩을 고려해야 하는 이유는 무엇입니까? 문자열이 저장된 바이트를 간단히 가져올 수 없습니까? 문자 인코딩에 대한 종속성이 있는 이유는 무엇입니까?

그것이 올바른 방법이기 때문입니다. string 은 추상화입니다.

인코딩을 사용하면 잘못된 문자가 포함된 '문자열'이 있는 경우 문제가 발생할 수 있지만 그렇게 해서는 안 됩니다. 잘못된 문자로 문자열에 데이터를 가져오는 경우 잘못하고 있는 것입니다. 시작하려면 바이트 배열이나 Base64 인코딩을 사용해야 할 것입니다.

System.Text.Encoding.Unicode 를 사용하면 코드가 더 탄력적입니다. 코드가 실행될 시스템 의 엔디안(endianness) 에 대해 걱정할 필요가 없습니다. CLR의 다음 버전에서 다른 내부 문자 인코딩을 사용할지 걱정할 필요가 없습니다.

문제는 인코딩에 대해 걱정하려는 이유가 아니라 무시하고 다른 것을 사용하려는 이유라고 생각합니다. 인코딩은 바이트 시퀀스에서 문자열의 추상화를 나타내기 위한 것입니다. System.Text.Encoding.Unicode 는 리틀 엔디안 바이트 순서 인코딩을 제공하고 현재와 미래의 모든 시스템에서 동일하게 수행합니다.


Jason Goemaat

다음 코드를 사용하여 .NET에서 stringbyte array 로 변환할 수 있습니다.

 string s_unicode = "abcéabc"; byte[] utf8Bytes = System.Text.Encoding.UTF8.GetBytes(s_unicode);

Shyam sundar shah

바이트로 무엇을 할 것인지 묻는 질문에 다음과 같이 대답했습니다 .

암호화하겠습니다. 변환하지 않고 암호화할 수 있지만 여기에서 인코딩이 재생되는 이유를 알고 싶습니다. 그냥 나에게 바이트를 제공 내가 말하는 것입니다.

이 암호화된 데이터를 네트워크를 통해 보낼 것인지, 나중에 메모리에 다시 로드할 것인지, 아니면 다른 프로세스로 증기할 것인지 여부에 관계없이 분명히 언젠가는 해독할 의도가 있습니다. 이 경우, 대답은 통신 프로토콜을 정의하고 있다는 것입니다. 통신 프로토콜은 프로그래밍 언어 및 관련 런타임의 구현 세부 사항 측면에서 정의되어서는 안 됩니다. 여기에는 몇 가지 이유가 있습니다.

  • 다른 언어나 런타임으로 구현된 프로세스와 통신해야 할 수도 있습니다. (예를 들어, 여기에는 다른 컴퓨터에서 실행 중인 서버나 JavaScript 브라우저 클라이언트에 문자열을 보내는 것이 포함될 수 있습니다.)
  • 프로그램은 향후 다른 언어 또는 런타임으로 다시 구현될 수 있습니다.
  • .NET 구현은 문자열의 내부 표현을 변경할 수 있습니다. 말도 안 되는 소리라고 생각할 수도 있지만 이것은 메모리 사용량을 줄이기 위해 Java 9에서 실제로 발생했습니다. .NET이 따라가지 못할 이유가 없습니다. Skeet은 현재 UTF-16이 최적이 아닐 수 있다고 제안합니다. 이모지 및 표현하는 데 2바이트 이상을 필요로 하는 유니코드의 기타 블록이 증가하여 향후 내부 표현이 변경될 가능성이 높아집니다.

통신을 위해(완전히 다른 프로세스로 또는 미래에 동일한 프로그램으로), 프로토콜을 사용하여 작업하거나 실수로 버그를 생성하는 어려움을 최소화하기 위해 프로토콜을 엄격하게 정의해야 합니다. .NET의 내부 표현에 따라 엄격하거나 명확하지 않거나 일관된 정의가 보장되지 않습니다. 표준 인코딩 미래에 실패하지 않을 엄격한 정의입니다.

즉, 인코딩을 지정하지 않고 는 일관성 요구 사항을 충족할 수 없습니다.

당신은 확실히 당신이 찾아내는 경우 직접 UTF-16을 사용하도록 선택할 수 프로세스가 수행하는 훨씬 더 나은 .NET 내부적으로 또는 다른 이유로 그것을 사용하지만, 명시 적으로 인코딩하는 것을 선택하고 따라보다 코드에서 명시 적으로 이러한 변환을 대신 수행 할 필요가 있기 때문에 .NET의 내부 구현에서.

따라서 인코딩을 선택하고 사용하십시오.

 using System.Text; // ... Encoding.Unicode.GetBytes("abc"); # UTF-16 little endian Encoding.UTF8.GetBytes("abc")

보시다시피, 자체 판독기/작성기 메서드를 구현하는 것보다 기본 제공 인코딩 개체를 사용하는 것이 실제로 코드가 적습니다.


jpmc26

문자열의 기본 바이트 복사본을 정말로 원하면 다음과 같은 함수를 사용할 수 있습니다. 그러나 그 이유를 계속 읽어서는 안 됩니다.

 [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()

Jodrell

String to 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; }

비록 그것이 우아하지 않더라도 허용된 wser의 것보다 훨씬 빠릅니다. 다음은 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 } }

Tommaso Belluzzo

문자열은 다음과 같은 사실 때문에 몇 가지 다른 방법으로 바이트 배열로 변환할 수 있습니다. .NET은 유니코드를 지원하고 유니코드는 UTF라고 하는 여러 가지 다른 인코딩을 표준화합니다. 그것들은 바이트 표현의 길이가 다르지만 문자열이 인코딩될 때 문자열로 다시 코딩될 수 있다는 점에서 동일합니다. 위로.

또한 .NET은 비유니코드 인코딩을 지원하지만 일반적인 경우에는 유효하지 않습니다(유니코드 코드 포인트의 제한된 하위 집합이 ASCII와 같은 실제 문자열에서 사용되는 경우에만 유효합니다). 내부적으로 .NET은 UTF-16을 지원하지만 스트림 표현의 경우 일반적으로 UTF-8이 사용됩니다. 또한 인터넷에 대한 사실상의 표준입니다.

당연히 문자열을 바이트 배열로 직렬화하고 역직렬화를 지원하는 것은 추상 클래스인 System.Text.Encoding 파생 클래스는 구체적인 인코딩을 지원합니다: ASCIIEncoding 및 4개의 System.Text.UnicodeEncoding 은 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? :-)

Vijay Singh Rana

그것은 당신이 원하는 바이트에 달려 있습니다

타일러가 적절하게 말했듯 이 "문자열은 순수한 데이터가 아닙니다. 정보 도 있습니다." 이 경우 정보는 문자열이 생성될 때 가정된 인코딩입니다.

문자열에 저장된 바이너리 데이터(텍스트가 아닌)가 있다고 가정합니다.

이것은 자신의 질문에 대한 OP의 의견을 기반으로하며 유스 케이스에 대한 OP의 힌트를 이해하는 경우 올바른 질문입니다.

이진 데이터를 문자열에 저장하는 것은 위에서 언급한 가정된 인코딩 때문에 아마도 잘못된 접근 방식일 것입니다! byte[] 배열 대신에) string 에 저장한 프로그램이나 라이브러리는 전투가 시작되기 전에 이미 패배했습니다. 그들이 REST 요청/응답 또는 문자열을 전송 해야 하는 모든 것으로 바이트를 보내는 경우 Base64 가 올바른 접근 방식이 될 것입니다.

알 수 없는 인코딩의 텍스트 문자열이 있는 경우

다른 모든 사람들은 이 잘못된 질문에 잘못 대답했습니다.

문자열이 있는 그대로 좋아 보인다면 인코딩(UTF로 시작하는 것이 바람직함)을 선택하고 해당 System.Text.Encoding.???.GetBytes() 함수를 사용하고 누구에게 바이트를 어떤 인코딩에 지정했는지 알려주십시오. 고른.


NH.

.NET Framework.NET Core 또는 System.Memory 를 사용하는 경우 문자열 메모리를 바이트 범위로 효과적으로 재해석할 수 있는 Span<T>Memory<T> 를 통해 사용할 수 있는 매우 효율적인 마샬링 메커니즘이 있습니다. 바이트 범위가 있으면 다른 유형으로 다시 마샬링하거나 직렬화를 위해 범위를 배열에 복사할 수 있습니다.

다른 사람들의 말을 요약하자면 다음과 같습니다.

  • 이러한 종류의 직렬화 표현을 저장하는 것은 시스템 엔디안, 컴파일러 최적화 및 실행 중인 .NET 런타임에서 문자열의 내부 표현에 대한 변경 사항에 민감합니다.
    • 장기간 보관을 피하십시오
    • 다른 환경에서 문자열을 역직렬화하거나 해석하지 마십시오.
      • 여기에는 다른 시스템, 프로세서 아키텍처, .NET 런타임, 컨테이너 등이 포함됩니다.
      • 여기에는 비교, 형식 지정, 암호화, 문자열 조작, 현지화, 문자 변환 등이 포함됩니다.
    • 문자 인코딩에 대한 가정을 피하십시오.
      • 기본 인코딩은 실제로 UTF-16LE인 경향이 있지만 컴파일러/런타임은 내부 표현을 선택할 수 있습니다.

구현

 public static class MarshalExtensions { public static ReadOnlySpan<byte> AsBytes(this string value) => MemoryMarshal.AsBytes(value.AsSpan()); public static string AsString(this ReadOnlySpan<byte> value) => new string(MemoryMarshal.Cast<byte, char>(value)); }

예시

 static void Main(string[] args) { string str1 = "你好,世界"; ReadOnlySpan<byte> span = str1.AsBytes(); string str2 = span.AsString(); byte[] bytes = span.ToArray(); Debug.Assert(bytes.Length > 0); Debug.Assert(str1 == str2); }

푸르투어 인사이트

C++에서 이것은 reinterpret_cast 와 대략 동일하고 C는 시스템의 단어 유형( char )으로의 캐스트와 대략 동일합니다.

최신 버전의 .NET Core Runtime(CoreCLR) 에서 범위에 대한 작업은 때때로 경계 검사를 제거할 수 있는 컴파일러 내장 함수 및 다양한 최적화를 효과적으로 호출하여 메모리가 CLR 및 범위는 관리되지 않는 메모리 할당자의 포인터에서 파생되지 않습니다.

주의 사항

이것은 문자열에서 ReadOnlySpan<char> 을 반환하는 CLR에서 지원하는 메커니즘을 사용합니다. 또한 이 범위는 전체 내부 문자열 레이아웃을 반드시 포함하지는 않습니다. ReadOnlySpan<T> 은 문자열을 변경할 수 없으므로 변형을 수행해야 하는 경우 복사본을 만들어야 함을 의미합니다.


Chris Hutchinson

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

user1120193

다음을 사용하기만 하면 됩니다.

 byte[] myByte= System.Text.ASCIIEncoding.Default.GetBytes(myString);

alireza amini

출처 : http:www.stackoverflow.com/questions/472906/how-do-i-get-a-consistent-byte-representation-of-strings-in-c-sharp-without-manu

반응형