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


2189

특정 인코딩을 수동으로 지정하지 않고 stringa byte[]를 .NET (C #)으로 변환하려면 어떻게해야 합니까?

문자열을 암호화하겠습니다. 변환하지 않고 암호화 할 수는 있지만 여전히 인코딩이 왜 작동하는지 알고 싶습니다.

또한 인코딩을 고려해야하는 이유는 무엇입니까? 문자열이 저장된 바이트를 간단히 얻을 수 없습니까? 문자 인코딩에 의존하는 이유는 무엇입니까?


23
모든 문자열은 바이트 배열로 저장됩니까? 왜 단순히 그 바이트를 가질 수 없습니까?
Agnel Kurian

135
인코딩 문자를 바이트에 매핑하는 것입니다. 예를 들어 ASCII에서 문자 'A'는 숫자 65에 매핑됩니다. 다른 인코딩에서는 같지 않을 수 있습니다. .NET 프레임 워크에서 가져온 문자열에 대한 높은 수준의 접근 방식은이 경우를 제외하고는 크게 관련이 없습니다.
Lucas Jones

20
악마의 옹호자를 재생하려면 : .NET에서 사용하는 것처럼 메모리 내 문자열의 바이트를 가져 와서 어떻게 든 조작 (예 : CRC32)하려는 경우 절대로 원래 문자열로 다시 디코딩하지 않으려는 경우 ... it 인코딩에 관심이 있거나 사용할 인코딩을 선택하는 방법이 간단하지 않습니다.
Greg Greg

78
놀랍게도 아직 아무도이
Bevan

28
문자는 바이트가 아니며 바이트는 문자가 아닙니다. 문자는 글꼴 테이블과 어휘 전통의 열쇠입니다. 문자열은 일련의 문자입니다. (단어, 단락, 문장 및 제목에는 자체 유형 정의를 정당화하는 고유 한 어휘 전통이 있지만 필자는 틀립니다). 정수, 부동 소수점 숫자 및 기타 모든 것과 마찬가지로 문자는 바이트로 인코딩됩니다. 인코딩이 단순한 일대일 인 ASCII가있었습니다. 그러나, 모든 인간 상징을 수용하기 위해, 바이트의 256 순열이 불충분하고, 더 많은 바이트를 선택적으로 사용하도록 인코딩이 고안되었다.
George

답변:


1855

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

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

이러한 목표를 위해 사람들 이 왜 인코딩이 필요하다는 것을 계속 말하고 있는지 이해 하지 못합니다 . 이를 위해 인코딩에 대해 걱정할 필요는 없습니다.

대신이 작업을 수행하십시오.

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 만보 고 있기 때문에 똑같이 인코딩되고 디코딩 됩니다 .

그러나 특정 인코딩을 사용한 경우 유효하지 않은 문자를 인코딩 / 디코딩하는 데 문제가있을 수 있습니다.


247
어떤 추한 것은이 것입니다에 대해 그 GetStringGetBytes작업에 동일한 엔디안있는 시스템에서 실행해야합니다. 따라서 다른 곳에서 문자열로 바꾸려는 바이트를 얻는 데 이것을 사용할 수 없습니다. 그래서 저는 이것을 사용하고 싶은 상황을 생각해 내기가 어렵습니다.
코드 InChaos

72
@ CodeInChaos : 내가 말했듯이, 이것의 요점은 동일한 기능 세트로 동일한 종류의 시스템에서 사용하려는 경우입니다. 그렇지 않으면 사용하지 않아야합니다.
user541686

193
-1 바이트 (문자와 문자를 이해하지 못하는 사람)가 문자열을 바이트 배열로 변환하고 싶을 때 구글 에서이 답변을 읽고 잘못 할 것입니다. 케이스는, 부호화는 IS 중요한.
artbristol 2016 년

401
@ artbristol : 그들이 대답 (또는 다른 대답 ...)을 읽도록 귀찮게 할 수 없다면 미안합니다. 그들과 의사 소통하는 더 좋은 방법은 없습니다. 나는 일반적으로 다른 사람이 내 대답으로 무엇을 할 수 있는지 추측하려고하기보다는 OP에 응답하기로 선택합니다. OP에는 알 권리가 있으며 누군가 칼을 남용한다고해서 세계의 모든 나이프를 숨겨야한다는 의미는 아닙니다. 우리 자신을 위해. 당신이 동의하지 않으면 그것도 괜찮습니다.
user541686

185
이 답변은 많은 수준에서 잘못되었지만 무엇보다도 "인코딩에 대해 걱정할 필요가 없습니다!"라는 편각 때문입니다. GetBytes 및 GetString의 두 가지 메소드는 Encoding.Unicode.GetBytes () 및 Encoding.Unicode.GetString ()이 이미 수행 한 작업을 단순히 다시 구현하는 것만 큼 불필요합니다. "프로그램 (또는 다른 프로그램)이 바이트를 해석하려고 시도하지 않는 한"이라는 문장도 암시 적으로 바이트에 유니 코드로 해석되어야 함을 암시 적으로 결함이 있습니다.
David

1108

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


14
그러나 인코딩을 고려해야하는 이유는 무엇입니까? 어떤 인코딩이 사용되고 있는지 보지 않고 단순히 바이트를 얻을 수없는 이유는 무엇입니까? 필요한 경우에도 String 객체 자체가 어떤 인코딩이 사용되고 있는지 알고 메모리에있는 것을 단순히 덤프해서는 안됩니까?
Agnel Kurian

57
.NET 문자열은 항상 유니 코드로 인코딩됩니다. 따라서 System.Text.Encoding.Unicode.GetBytes ()를 사용하십시오. .NET이 문자를 나타내는 데 사용할 바이트 세트를 가져옵니다. 그러나 왜 그렇게 하시겠습니까? 특히 대부분의 문자가 서부 라틴어 세트 인 경우 UTF-8을 권장합니다.
AnthonyWJones

8
또한 문자열에서 내부적으로 사용되는 정확한 바이트 는 검색하는 시스템이 해당 인코딩을 처리하지 않거나 잘못된 인코딩으로 처리하는 경우 중요 하지 않습니다. 그것이 모두 .Net에 있다면 왜 바이트 배열로 변환해야합니까? 그렇지 않으면, 당신의 인코딩을 명시하는 것이 좋습니다
조엘 Coehoorn

11
@Joel, System.Text.Encoding.Default는 실행되는 시스템마다 다를 수 있으므로주의하십시오. 따라서 항상 UTF-8과 같은 인코딩을 지정하는 것이 좋습니다.
Ash

25
데이터를 일반적인 "바이트 블록"으로 취급하지 않고 실제로 데이터 를 해석 하려고하지 않는 한 인코딩이 필요하지 않습니다 . 압축, 암호화 등의 경우 인코딩에 대한 걱정은 의미가 없습니다. 인코딩에 대해 걱정하지 않고이 작업을 수행하는 방법 은 내 답변 을 참조하십시오 . (필요하지 않을 때 인코딩에 대해 걱정할 필요가 있다고 말하면 -1을 주었을 수도 있지만 오늘은 특별히 의미가 없다고 생각합니다. : P)
user541686

285

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

당신이 필요하지 않은 경우 바퀴를 재발 명하지 마십시오 ...


14
수락 된 답변이 변경 될 경우 기록적인 목적으로이 현재 시간 및 날짜에 대한 Mehrdad의 답변입니다. OP가 이것을 다시 방문하여 더 나은 솔루션을 받아들이기를 바랍니다.
Thomas Eding

7
원칙적으로는 좋지만 인코딩은 System.Text.Encoding.UnicodeMehrdad의 답변과 동일 해야합니다 .
Jodrell

5
질문은 원래 답변 이후 umptillion 시간으로 편집되었으므로 내 대답이 약간 오래되었습니다. 나는 Mehrdad의 대답과 동등한 Exace를 제공하려고 의도하지 않았지만 합리적인 방법을 제시했습니다. 그러나 당신이 옳을 수도 있습니다. 그러나 원래 질문에서 "문자열이 저장된 바이트를 얻습니다"라는 문구는 매우 정확하지 않습니다. 어디에 보관 했습니까? 기억에? 디스크에? 메모리에 있다면 System.Text.Encoding.Unicode.GetBytes아마도 더 정확할 것입니다.
Erik A. Brandstadmoen

7
@AMissico, 문자열이 시스템 기본 인코딩 (시스템 기본 레거시 문자 세트에 ASCII 문자 만 포함하는 문자열)과 호환되는지 확실하지 않은 한 제안은 버그가 있습니다. 그러나 OP가 언급하지 않는 곳은 없습니다.
Frédéric

5
@AMissico 프로그램 에 따라 시스템 마다 다른 결과가 나올 수 있습니다 . 즉 없습니다 결코 좋은 일이. 해시 또는 무언가를 만들기위한 경우 (OP가 '암호화'로 의미하는 것으로 가정 함)에도 동일한 문자열은 항상 동일한 해시를 제공해야합니다.
Nyerguds

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

2
당신은 그 모든 조작 같은 경우 BinaryFormatter 인스턴스를 사용할 수 있습니다
조엘 Coehoorn

3
매우 흥미로운. 분명히 그것은 대리 유니 코드 문자를 떨어 뜨릴 것입니다. 에 대한 설명서를 참조하십시오 [경우 BinaryFormatter ]

95

1 개의 문자는 1 개 이상의 바이트 (최대 약 6 개) 로 표현 될 수 있으므로 인코딩을 고려해야 하며, 다른 인코딩은 이러한 바이트를 다르게 취급합니다.

Joel은 이것에 대해 글을 올렸습니다 :

절대적으로 모든 소프트웨어 개발자는 반드시 유니 코드 및 문자 집합에 대해 반드시 알아야합니다 (변명 없음).


6
"1 문자는 1 바이트 이상으로 표현 될 수 있습니다"라고 동의합니다. 문자열이 어떤 인코딩인지에 관계없이 바이트를 원합니다. 문자열을 메모리에 저장할 수있는 유일한 방법은 바이트입니다. 문자도 1 바이트 이상으로 저장됩니다. 나는 단지 그들에게 바이트를주고 싶어한다.
Agnel Kurian

16
데이터를 일반적인 "바이트 블록"으로 취급하지 않고 실제로 데이터 를 해석 하려고하지 않는 한 인코딩이 필요하지 않습니다 . 압축, 암호화 등의 경우 인코딩에 대한 걱정은 의미가 없습니다. 인코딩에 대해 걱정하지 않고이 작업을 수행하는 방법 은 내 답변 을 참조하십시오 .
user541686

9
@Mehrdad-처음에 대답했을 때 언급 한 것처럼 원래 질문은 OP가 변환 된 후 해당 바이트에서 어떤 일이 발생할 지주의하지 않았으며 향후 검색 자에게는 관련 정보가 관련이 있습니다. 적용 조엘의 대답은 아주 능숙하게 - 당신의 대답은 내 당신이 상태로 : 당신이있는 거 행복, 닷넷 세계에서 스틱과에서 /로 변환하기 위해 방법을 사용하여 제공. 그 단계를 벗어나면 인코딩이 중요합니다.
Zhaph-Ben Duguid

하나의 코드 포인트 는 최대 4 바이트 로 표시 할 수 있습니다 . (하나의 UTF-32 코드 단위, UTF-16 서로 게이트 쌍 또는 UTF-8의 4 바이트) UTF-8에 4 바이트 이상이 필요한 값은 0x0..0x10FFFF 유니 코드 범위를 벗어납니다. ;-)
DevSolar

89

이것은 인기있는 질문입니다. 질문 작성자가 요구하는 내용을 이해하고 가장 일반적인 요구와 다른 점을 이해하는 것이 중요합니다. 필요하지 않은 코드의 오용을 막기 위해 나중에 먼저 답변했습니다.

일반적인 필요

모든 문자열에는 문자 세트와 인코딩이 있습니다. 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가 지적했듯이 결과는 기계의 엔디안에 달려 있습니다. 그러나 질문 저자는 그것에 관심이 없습니다.


3
@ Jan 정확하지만 문자열 길이는 이미 코드 단위가 아닌 코드 단위 수를 제공합니다.
Tom Blodget

1
지적 해 주셔서 감사합니다! MSDN에서 : " Length[of String] 속성 Char은이 인스턴스에서 유니 코드 문자 수가 아닌 개체 수를 반환합니다 ." 따라서 예제 코드는 작성된대로 정확합니다.
Jan Hettich

1
@supercat "문자 유형은 UTF-16 코드 단위를 나타내고 문자열 유형은 UTF-16 코드 단위의 시퀀스를 나타냅니다."—_ C # 5 Specification._ 그렇습니다. 그러나 잘못된 유니 코드 문자열을 막을 수있는 것은 없습니다.new String(new []{'\uD800', '\u0030'})
Tom Blodget 오전

1
@TomBlodget : 하나의 인스턴스 걸리면 흥미롭게도 Globalization.SortKey, 추출 KeyData(A) 내로 각각의 행 및 팩 생성 바이트 String[문자 당 2 바이트 MSB 먼저 , 호출 String.CompareOrdinal결과 스트링에 것은 전화보다 훨씬 빠르다 SortKey.Compare의 인스턴스 SortKey또는 심지어 memcmp그 인스턴스를 호출 합니다. 내가 왜 궁금 점을 감안 KeyData반환 Byte[]보다는를 String?
supercat

1
정답이지만 몇 년이 늦어도 알래스카는 허용 된만큼 많은 표를 얻지 못할 것입니다. TL; DR로 인해 사람들은 받아 들여진 대답이 바위라고 생각합니다. 복사하여 붙여 넣습니다.
Martin Capodici 2016 년

46

귀하의 질문의 첫 번째 부분 (바이트를 얻는 방법)은 이미 다른 사람들에 의해 답변되었습니다 : System.Text.Encoding네임 스페이스를보십시오.

다음 질문에 답하겠습니다. 왜 인코딩을 선택해야합니까? 왜 문자열 클래스 자체에서 얻을 수 없습니까?

답은 두 부분으로되어 있습니다.

우선, 문자열 클래스 내부적으로 사용하는 바이트 는 중요하지 않으며 ,이를 가정 할 때마다 버그가 발생할 수 있습니다.

프로그램이 전적으로 .Net 세계에있는 경우 네트워크를 통해 데이터를 전송하더라도 문자열에 대한 바이트 배열을 얻는 것에 대해 걱정할 필요가 없습니다. 대신 .Net Serialization을 사용하여 데이터 전송에 대해 걱정하십시오. 더 이상 실제 바이트에 대해 걱정하지 않아도됩니다. Serialization 포맷터가이를 대신합니다.

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

이 경우 가능한 경우 메모리에 문자열 변수로 저장된 실제 바이트를 바이트 스트림을 만드는 일부 작업을 저장할 수 있다는 아이디어와 함께 사용하는 것이 좋습니다. 그러나 출력을 다른 쪽 끝에서 이해하고 인코딩으로 명시 적으로 보장 해야하는 것과 비교하여 중요하지 않습니다 . 또한 내부 바이트와 실제로 일치 시키려면 이미 Unicode인코딩을 선택하고 성능을 향상시킬 수 있습니다.

어느 따기 ... 두 번째 부분에 저를 가져다 Unicode인코딩 되는 기본 바이트를 사용하는 닷넷 이야기. 새로운 인코딩 된 Unicode-Plus가 나올 때 .Net 런타임은 프로그램을 중단하지 않고이 새롭고 더 나은 인코딩 모델을 자유롭게 사용할 수 있어야하므로이 인코딩을 선택해야합니다. 그러나 당분간 (그리고 미래에도) 유니 코드 인코딩을 선택하면 원하는 것을 얻을 수 있습니다.

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


9
.NET에는 문자열의 바이트 배열을 가져와야하는 영역이 있습니다. 많은 .NET Cryptrography 클래스에는 바이트 배열 또는 스트림을 허용하는 ComputeHash ()와 같은 메서드가 포함되어 있습니다. 문자열을 먼저 바이트 배열로 변환 한 다음 (인코딩 선택) 스트림에 래핑 할 수도 있습니다. 그러나 인코딩 (예 : UTF8)을 사용하는 스틱에는 문제가 없습니다.
Ash

44

그냥 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

谢谢!


3
유효한 코드 포인트를 형성하기 위해 서로 게이트를 쌍으로 표시 할 필요가 없습니까? 이 경우 데이터가 엉망인 이유를 이해할 수 있습니다.
dtanders

1
@dtanders 예, 저도 제 생각이기도합니다. 짝을 이루지 않은 대리 문자는 의도적으로 문자열에 넣고 짝을 짓지 않으면 발생합니다. 다른 DEVS들이 (직렬화 방법으로 간주 우리가 대신 인코딩 인식 방식을 사용한다는 것을 하프 소리가 계속 나면서 계속 왜 내가 모르는 것은 내 대답 홑를 유지하지 않습니다 3 년 이상에 대한 허용 대답했다) 대리 문자 그대로. 그러나 그들은 자신의 인코딩 인식 솔루션이 짝을 이루지 않은 대리 문자도 유지하지 않는 것을 확인하는 것을 잊었습니다. 아이러니 ツ
Michael Buen

System.Buffer.BlockCopy내부적으로 사용하는 직렬화 라이브러리가 있다면 , 모든 인코딩 옹호론자들의 주장은 불분명 할 것입니다
Michael Buen

2
@MichaelBuen 주된 문제는 당신이 큰 문제로 대담한 글씨로되어 있다는 것입니다. 대소 문자는 중요하지 않습니다. 결과적으로, 당신은 당신의 대답을보고있는 사람들에게 기본 프로그래밍 실수를하도록 장려하고 있습니다. 짝을 이루지 않은 서로 게이트는 문자열에서 유효하지 않습니다. char 배열이 아니므로 문자열을 다른 형식으로 변환하면 FFFD해당 문자에 오류가 발생 합니다. 수동 문자열 조작을 수행하려면 권장되는대로 char []를 사용하십시오.
Trisped

2
@dtanders : A System.String는 불변 시퀀스이며 Char; .NET은 원본 에 짝을 이루지 않은 서로 게이트가 포함되어 있어도 String개체를 항상 구성 하여 동일한 값을 포함하는 Char[]내용으로 내 보냅니다 . Char[]Char[]
supercat 2011

41

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

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
mg30rg

9
@ mg30rg : 왜 당신의 예가 이상하다고 생각합니까? 가변 폭 인코딩에서 모든 문자의 바이트 길이가 동일한 것은 아닙니다. 무슨 일이야?
블라드

@Vlad 여기서보다 유효한 설명은 인코딩 된 유니 코드 기호 (바이트)와 같이 고유 한 분음 부호 를 포함 하는 문자 분음 부호가 문자에 추가 된 수정 자 기호로 분리 된 것과는 다른 결과를 제공한다는 것 입니다. 그러나 iirc는 일관된 바이트 표현을 얻을 수 있도록 .net에 메소드를 구체적으로 분리하는 메소드가 있습니다.
Nyerguds

25

글쎄, 나는 모든 대답을 읽었으며 그들은 짝을 이루지 않은 대리자를 버리는 인코딩 또는 직렬화에 관한 것입니다.

예를 들어, 문자열 이 암호 해시와 같은 바이트 배열을 저장하는 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);
}

바이트 배열을 base64로 변환하기 위해 사용자 지정 방법을 사용하는 대신 내장 변환기를 사용하기 만하면됩니다. Convert.ToBase64String (arr);
Makotosan

@Makotosan은 감사하지만 Convert.ToBase64String(arr); base64 변환에는 사용 했습니다 byte[] (data) <-> string (serialized data to store in XML file). 그러나 초기를 얻으려면 바이너리 데이터 가 포함 된 byte[] (data)무언가를 수행해야 했습니다 (MSSQL이 나에게 그것을 반환 한 방식입니다). 따라서 위의 기능은입니다 . StringString (binary data) <-> byte[] (easy accessible binary data)
Gman

23

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

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

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

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

즉, "인코딩을 사용하지 않고 문자열의 바이트를 얻는"것은 "언어를 사용하지 않고 텍스트를 작성"하는 것만 큼 불가능합니다.

그건 그렇고, 나는 당신과 그 문제에 대해이 작은 지혜를 읽을 것을 강력히 권장합니다 . 절대적으로 모든 소프트웨어 개발자는 절대적으로 유니 코드와 문자 세트에 대해 알아야합니다 (변명 없음!)


2
명확히하겠습니다 : "hello world"를 물리 바이트로 변환하기 위해 인코딩이 사용되었습니다. 문자열이 내 컴퓨터에 저장되어 있기 때문에 바이트로 저장해야합니다. 디스크 또는 다른 이유로 저장하기 위해 해당 바이트에 액세스하고 싶습니다. 이 바이트를 해석하고 싶지 않습니다. 이러한 바이트를 해석하고 싶지 않기 때문에이 시점에서 인코딩이 필요한 것은 printf를 호출하기 위해 전화선을 요구하는 것만 큼 잘못되었습니다.
Agnel Kurian

3
그러나 다시 인코딩을 사용하지 않으면 텍스트-물리적 바이트 변환 개념이 없습니다. 물론 컴파일러는 문자열을 어떻게 든 메모리에 저장하지만 내부 인코딩을 사용하고 있습니다 (또는 컴파일러 개발자를 제외한 모든 사람)는 알 수 없습니다. 따라서 무엇을 하든지 문자열에서 실제 바이트를 얻으려면 인코딩이 필요합니다.
Konamiman

@Agnel Kurian : 물론 문자열에 내용을 저장하는 바이트가 많이 있습니다 (UTF-16 afair). 그러나 문자열에 액세스 할 수없는 좋은 이유가 있습니다. 문자열은 변경할 수 없으며 내부 byte [] 배열을 얻을 수 있으면이를 수정할 수도 있습니다. 이것은 여러 문자열이 동일한 데이터를 공유 할 수 있기 때문에 불변성을 깨뜨립니다. UTF-16 인코딩을 사용하여 문자열을 가져 오면 아마도 데이터가 복사 될 것입니다.
ollb

2
@Gnafoo, 바이트 사본이 할 것입니다.
Agnel Kurian

22

a stringbyte배열 로 변환하는 C # :

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

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

그러나 인코딩을 고려해야하는 이유는 무엇입니까? 어떤 인코딩이 사용되고 있는지 보지 않고 단순히 바이트를 얻을 수없는 이유는 무엇입니까? 필요한 경우에도 String 객체 자체가 어떤 인코딩이 사용되고 있는지 알고 메모리에있는 것을 단순히 덤프해서는 안됩니까?
Agnel Kurian

5
항상 작동하지는 않습니다. 내가 찾은 그런 방법을 사용하면 일부 특수 문자가 사라질 수 있습니다.
JB King

17

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

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

VUP이 내 문제를 해결 (byte [] ff = ASCIIEncoding.ASCII.GetBytes (barcodetxt.Text);)
r.hamd

16

의 출현 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);
    }
}

이름 NonPortableCastDangerousGetPinnableReference당신이 아마 이것을해서는 안된다는 주장을 더해야합니다.

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

에 관계없이 실제 원래의 질문과 의견을 후속는 기본 메모리가 나타내는 (I 수정 또는있는 그대로를 작성할 필요 이상으로 읽을 수 없습니다되는 수단을 가정한다) "해석"되지 않는 것을 의미 그 일부 구현 Stream클래스 데이터를 문자열로 추론하는 대신 사용해야합니다.


13

확실하지 않지만 문자열은 정보를 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하면되지만 저장 공간이 비효율적입니다.


10

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

Utf8은 널리 사용되는 인코딩이며 크기가 작고 손실이 없습니다.


3
UTF-8은 대부분의 문자가 영어 (ASCII) 문자 세트 인 경우에만 압축됩니다. 한자 문자열이 긴 경우 UTF-16은 해당 문자열의 UTF-8보다 더 컴팩트 한 인코딩입니다. UTF-8은 1 바이트를 사용하여 ASCII를 인코딩하고 그렇지 않으면 3 (또는 4)을 사용하기 때문입니다.
Joel Mueller

7
진실. 그러나 중국어 텍스트 처리에 익숙하다면 인코딩에 대해 어떻게 알 수 있습니까?
Hans Passant

9

사용하다:

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

결과는 다음과 같습니다.

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

OP는 구체적으로 인코딩을 지정하지 말 것을 요청합니다 ... "특정 인코딩을 수동으로 지정하지 않고"
Ferdz

8

가장 빠른 방법

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

편집 Makotosan 등이 지금 최선의 방법입니다 주석 :

Encoding.UTF8.GetBytes(text)

8
ASCIIEncoding .....은 필요하지 않습니다. Encoding.UTF8.GetBytes (text)를 사용하는 것이 좋습니다.
Makotosan 2019

8

특정 인코딩을 수동으로 지정하지 않고 .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약간의 엔디 언 바이트 순서 인코딩을 제공하며 현재와 미래의 모든 시스템에서 동일하게 수행됩니다.


실제로 C #의 문자열은 UTF-16으로 만 제한되지 않습니다. 사실 16 비트 코드 단위로 구성된 벡터가 포함되어 있지만이 16 비트 코드 단위는 유효한 UTF-16으로 제한되지 않습니다. 그러나 16 비트이므로 8 비트로 변환하려면 인코딩 (바이트 순서)이 필요합니다. 그런 다음 문자열은 이진 코드 (예 : 비트 맵 이미지)를 포함하여 비 유니 코드 데이터를 저장할 수 있습니다. 이러한 해석을 수행하는 I / O 및 텍스트 포맷터에서만 UTF-16으로 해석됩니다.
verdy_p

따라서 C # 문자열에서 UTF-16의 문자가 아닌 경우에도 0xFFFF 또는 0xFFFE와 같은 코드 단위를 안전하게 저장할 수 있으며 0xDC00..0xDFFF에 코드 단위가 아닌 격리 된 0xD800을 저장할 수 있습니다. UTF-16에서는 유효하지 않은 쌍을 이루지 않은 서로 게이트). Javascript / ECMAscript 및 Java의 문자열에도 동일한 설명이 적용됩니다.
verdy_p

"GetBytes"를 사용할 때는 물론 인코딩을 지정하지 않지만 문자열에 로컬로 저장된 각 코드 단위에 대해 두 바이트를 특정 바이트 단위로 가져 오는 바이트 순서를 가정합니다. 바이트에서 새 문자열을 작성할 때 반드시 UTF-8에서 UTF-16으로 변환 할 필요는없는 변환기가 필요합니다. 상위 바이트에 여분의 0을 삽입하거나 2 바이트 (MSB 우선 또는 LSB 우선)를 동일한 16 비트 코드 단위 그런 다음 문자열은 16 비트 정수 배열에 대한 간단한 형식입니다. "문자"와의 관계는 또 다른 문제입니다. C #에서는 여전히 문자열로 표시되기 때문에 실제 유형이 아닙니다
verdy_p

7

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에 대한 해답입니다. 그래서-만약 당신이 어쨌든 변환하려고한다면 ... 왜 '인코딩'하지?


이러한 문자는 UTF-8 또는 UTF-16 또는 심지어 exapmle의 경우 UTF-32 ( & &)에서 지원되지 않습니다 . 따라서 당신은 틀릴 수 있으며 Mehrdad의 대답은 어떤 유형의 인코딩이 사용되는지 고려하지 않고 안전하게 변환됩니다. 񩱠(Char) 55906(Char) 55655
Mojtaba Rezaeian

Raymon, 문자는 이미 일부 유니 코드 값으로 표시되며 모든 유니 코드 값은 모든 utf로 표시 될 수 있습니다. 당신이 말하는 것에 대한 더 자세한 설명이 있습니까? 이 두 값 (또는 3 ..)에는 어떤 문자 인코딩이 있습니까?
Gerard ONeill

인코딩 범위에서 지원되지 않는 유효하지 않은 문자입니다. 이것은 그들이 100 % 쓸모 없다는 것을 의미하지는 않습니다. 인코딩에 관계없이 모든 유형의 문자열을 해당 바이트 배열로 변환하는 코드는 전혀 잘못된 솔루션이 아니며 원하는 경우 자체 사용법이 있습니다.
Mojtaba Rezaeian

1
좋아, 그럼 당신이 문제를 이해하지 못한다고 생각합니다. 우리는 이것이 유니 코드 호환 배열임을 알고 있습니다. 실제로 .net이기 때문에 UTF-16이라는 것을 알고 있습니다. 따라서 해당 문자는 존재하지 않습니다. 내부 표현 변경에 대한 내 의견을 완전히 읽지 못했습니다. 문자열은 인코딩 된 바이트 배열이 아닌 객체입니다. 그래서 나는 당신의 마지막 진술에 동의하지 않을 것입니다. 코드가 모든 유니 코드 문자열을 UTF 인코딩으로 변환하려고합니다. 이것은 당신이 원하는 것을 올바르게합니다.
Gerard ONeill

객체는 현재 상태의 객체를 설명하는 원래 데이터 시퀀스입니다. 따라서 프로그래밍 언어의 모든 데이터는 메모리에 객체의 상태를 유지해야 할 수 있으므로 바이트 배열로 변환 할 수 있습니다 (각 바이트는 8 비트를 정의 함). 파일 또는 메모리에 일련의 바이트를 저장하고 보유한 후 디스크에서 읽은 후 정수, bigint, 이미지, ASCII 문자열, UTF-8 문자열, 암호화 된 문자열 또는 사용자 정의 데이터 유형으로 캐스트 할 수 있습니다. 따라서 객체가 바이트 시퀀스와 다르다고 말할 수는 없습니다.
Mojtaba Rezaeian

6

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

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

3

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

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

3

여기 내 안전하지 않은 구현 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의 배수는? 그렇지 않으면 정렬되지 않은 읽기로 인해 실패합니다.
Jon Hanna

호출하는 것이 더 간단하지 memcpy않습니까? stackoverflow.com/a/27124232/659190
Jodrell

2

간단히 이것을 사용하십시오 :

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

2
... 그리고 점프 코프가 127보다 높은 모든 캐릭터를 잃습니다. 내 모국어로 "Árvíztűrő tükörfúrógép."를 쓰는 것은 완벽하게 유효합니다. 검색 할 수없는 정보 손실 System.Text.ASCIIEncoding.Default.GetBytes("Árvíztűrő tükörfúrógép.").ToString();을 반환 "Árvizturo tukörfurogép."합니다. (그리고 나는 당신이 모든 문자를 풀어 놓을 아시아 언어에 대해서는 언급하지 않았습니다.)
mg30rg

2

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

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

당연히 문자열을 바이트 배열로 직렬화 및 역 직렬화는 System.Text.Encoding추상 클래스 인 클래스 에서 지원됩니다 . 파생 클래스는 구체적인 인코딩을 지원합니다. ASCIIEncoding4 개의 System.Text.UnicodeEncodingUTF ( 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? :-)

2

그것은 당신이 원하는 바이트에 따라 달라집니다

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

문자열이 아닌 이진 데이터 (텍스트가 아닌)가 저장되어 있다고 가정

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

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

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

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

문자열이 그대로 좋아 보인다면 인코딩 (바람직하게는 UTF로 시작하는 인코딩)을 선택하고 해당 System.Text.Encoding.???.GetBytes()기능을 사용하고 선택한 인코딩을 바이트에 제공하는 사람에게 알려주십시오.


2

바이트로 무엇을 하려는지 묻는 질문에 다음과 같이 응답했습니다 .

암호화하겠습니다. 변환하지 않고 암호화 할 수는 있지만 여전히 인코딩이 왜 여기에서 이루어지는 지 알고 싶습니다. 나에게 바이트를 알려주십시오.

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

  • 다른 언어 또는 런타임으로 구현 된 프로세스와 통신해야 할 수도 있습니다. (예를 들어 다른 컴퓨터에서 실행되거나 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")

보다시피, 내장 된 인코딩 객체를 사용하는 독자적인 리더 / 라이터 메소드를 구현하는 것보다 실제로 코드가 적습니다.


1

두 가지 방법:

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

나는 바닥보다 더 자주 바닥을 사용하는 경향이 있으며 속도를 벤치마킹하지 않았습니다.


4
멀티 바이트 문자는 어떻습니까?
Agnel Kurian

c.ToByte ()은 비공개입니다 : S
Khodor

@AgnelKurian Msdn은 "이 메서드는 전달 된 Char 개체의 숫자 코드를 나타내는 부호없는 바이트 값을 반환합니다. .NET Framework에서 Char 개체는 16 비트 값입니다. 즉,이 메서드는 반환에 적합합니다. ASCII 문자 범위 또는 유니 코드 C0 컨트롤 및 기본 라틴 및 C1 컨트롤 및 라틴 -1 보조 범위 (U + 0000에서 U + 00FF까지)의 숫자 코드
mg30rg

1
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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.