C #에서 문자열을 바이트 배열로 변환


670

VB에서 C #으로 무언가를 변환하고 있습니다. 이 문장의 구문에 문제가 있습니다 :

if ((searchResult.Properties["user"].Count > 0))
{
    profile.User = System.Text.Encoding.UTF8.GetString(searchResult.Properties["user"][0]);
}

그런 다음 다음 오류가 표시됩니다.

인수 1 : 'object'에서 'byte []'로 변환 할 수 없습니다

'System.Text.Encoding.GetString (byte [])'에 대해 가장 오버로드 된 메소드 일치에 올바르지 않은 인수가 있습니다.

게시물을 기반으로 코드를 수정하려고 했지만 여전히 성공하지 못했습니다.

string User = Encoding.UTF8.GetString("user", 0);

어떤 제안?


1
유형은 searchResult.Properties["user"][0]무엇입니까? byte[]먼저 캐스팅 해보십시오
mshsayem

mshsayem은 내가가는 곳으로 갔다. (byte[])searchResult에 대한 캐스트가 누락 되었습니까?
해리슨

2
어떤 유형인지 확인해야합니다 Properties["user"][0]. 당신이 확실 경우는 바이트 배열은 다음과 같이 캐스트 할 수있어profile.User = System.Text.Encoding.UTF8.GetString((byte[])searchResult.Properties["user"][0]);
keyboardP

1
모든 소란이 필요하지 않은 것으로 나타났습니다. 결국 사용자 이름을 인코딩하지 않고 가져올 수 있습니다.
nouptime

3
왜 정답을 선택하지 않습니까?
Ali

답변:


1189

바이트 배열이 이미 있으면 해당 바이트 배열로 인코딩하는 데 사용 된 인코딩 유형을 알아야합니다.

예를 들어, 바이트 배열이 다음과 같이 생성 된 경우 :

byte[] bytes = Encoding.ASCII.GetBytes(someString);

다음과 같이 문자열로 다시 설정해야합니다.

string someString = Encoding.ASCII.GetString(bytes);

상속 한 코드에서 바이트 배열을 만드는 데 사용 된 인코딩을 찾으면 설정해야합니다.


3
Timothy, 나는 VB 코드를 살펴 보았고 언급 한대로 바이트 배열을 찾을 수없는 것 같습니다.
nouptime

검색 결과에서 속성 속성 유형은 무엇입니까?
Timothy Randall

내가 볼 수있는 것은 속성에 문자열로 숫자 항목이 첨부되어 있다는 것입니다. 그것이 당신이 나에게 묻는 것이 확실하지 않습니다.
nouptime

16
@AndiAR 시도 Encoding.UTF8.GetBytes (somestring)
OzBob

1
내 상황에서 Encoding.Unicode.GetBytes가 작동했지만 ASCII가 작동하지 않음을 발견했습니다.
Jeff

106

먼저 System.Text네임 스페이스를 추가하십시오.

using System.Text;

그런 다음이 코드를 사용하십시오.

string input = "some text"; 
byte[] array = Encoding.ASCII.GetBytes(input);

그것을 고치기를 바랍니다!


42

또한 확장 메소드 를 사용하여 string다음과 같이 유형에 메소드 를 추가 할 수 있습니다 .

static class Helper
{
   public static byte[] ToByteArray(this string str)
   {
      return System.Text.Encoding.ASCII.GetBytes(str);
   }
}

그리고 아래와 같이 사용하십시오 :

string foo = "bla bla";
byte[] result = foo.ToByteArray();

12
ASCII 인코딩을 사용하고 있다는 사실을 포함하도록 해당 메소드의 이름을 바 꾸었습니다. 같은 것 ToASCIIByteArray. 내가 사용하고있는 라이브러리가 ASCII를 사용하고 UTF-8 또는 더 현대적인 것을 사용한다고 가정하고 싫어.
T Blank

30
var result = System.Text.Encoding.Unicode.GetBytes(text);

3
다른 답변은 ASCII를 제안하지만 허용되는 답변이어야하지만 인코딩은 유니 코드 (UTF16) 또는 UTF8입니다.
Abel

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

대리 쌍 범위에 속하는 문자의 경우이 작업이 실패합니다. GetBytes에는 대리 쌍당 하나의 일반 문자가 누락되는 바이트 배열이 있습니다. GetString은 끝에 빈 문자를 갖습니다. 작동하는 유일한 방법은 Microsoft의 기본값이 UTF32이거나 대리 쌍 범위의 문자가 허용되지 않은 경우입니다. 아니면 내가 보지 못하는 것이 있습니까? 올바른 방법은 문자열을 바이트로 '인코딩'하는 것입니다.
Gerard ONeill

더 넓은 범위의 경우 #Timothy Randall의 솔루션과 비슷한 것을 사용할 수 있습니다 : using System; System.Text 사용; namespace 예제 {public class Program {public static void Main (string [] args) {문자열 s1 = "Hello World"; 문자열 s2 = "שלום עולם"; 문자열 s3 = "你好 , 世界!"; Console.WriteLine (Encoding.UTF8.GetString (Encoding.UTF8.GetBytes (s1))); Console.WriteLine (Encoding.UTF8.GetString (Encoding.UTF8.GetBytes (s2))); Console.WriteLine (Encoding.UTF8.GetString (Encoding.UTF8.GetBytes (s3))); }}}
Eran Yogev

17

Encoding.Default를 사용하지 않아야하는 이유 ...

@Randall의 답변은을 사용 Encoding.Default하지만 Microsoft 는 이에 대한 경고를 표시합니다 .

컴퓨터마다 다른 인코딩을 기본값으로 사용할 수 있으며 기본 인코딩은 단일 컴퓨터에서 변경 될 수 있습니다. 기본 인코딩을 사용하여 컴퓨터간에 스트리밍되거나 동일한 컴퓨터에서 다른 시간에 검색된 데이터를 인코딩 및 디코딩하면 해당 데이터가 잘못 변환 될 수 있습니다. 또한 Default 속성에서 반환 된 인코딩은 가장 적합한 대체를 사용하여 지원되지 않는 문자를 코드 페이지에서 지원하는 문자로 매핑합니다. 이러한 이유로 기본 인코딩을 사용하지 않는 것이 좋습니다. 인코딩 된 바이트가 올바르게 디코딩되도록하려면 UTF8Encoding 또는 UnicodeEncoding과 같은 유니 코드 인코딩을 사용해야합니다. 또한 더 높은 수준의 프로토콜을 사용하여 인코딩 및 디코딩에 동일한 형식이 사용되도록 할 수 있습니다.

기본 인코딩이 무엇인지 확인하려면 Encoding.Default.WindowsCodePage(내 경우에는 1250을 사용하십시오. 슬프게도 사전 정의 된 CP1250 인코딩 클래스는 없지만 객체는로 검색 할 수 있습니다 Encoding.GetEncoding(1250))를 사용하십시오.

Encoding.ASCII 7bit이므로 내 경우에는 작동하지 않습니다.

byte[] pass = Encoding.ASCII.GetBytes("šarže");
Console.WriteLine(Encoding.ASCII.GetString(pass)); // ?ar?e

... 그리고 UTF-8 인코딩을 대신 사용해야하는 이유 ...

기본 인코딩은 오해의 소지가 있습니다. .NET은 모든 곳에서 UTF-8을 실제 기본값으로 사용합니다 (20 비트 말에 8 비트 인코딩은 더 이상 사용되지 않습니다. 세기를 확인하십시오 Console.OutputEncoding.EncodingName). 따라서 코드에서 정의한 모든 상수는 기본적으로 UTF-8로 인코딩됩니다. 이것은 데이터 소스가 다른 인코딩이 아닌 한 사용해야합니다.

* 이것은 직접 거짓말 인 내 경우에는 UTF-8입니다 chcp.Windows 콘솔 (cmd)에서 852가 반환되며 현지화 된 시스템 명령 (ping과 같은) 은이 코드 페이지에 하드 코드가 있으므로 변경해서는 안됩니다

Microsoft의 권장 사항에 따라 :

var utf8 = new UTF8Encoding();
byte[] pass = utf8.GetBytes("šarže");
Console.WriteLine(utf8.GetString(pass)); // šarže

Encoding.UTF8 UTF-8 인코딩 인스턴스는 다른 사람이 권장하며 직접 또는 다음과 같이 사용할 수도 있습니다.

var utf8 = Encoding.UTF8 as UTF8Encoding;

... 항상 사용되는 것은 아닙니다

바이트 배열의 인코딩은 서방 국가에서는 유니 코드에서 "작동"해야하지만 동유럽에서와 같이 지원되지 않는 일부 지역으로 프로그램을 이동하자마자 정말 엉망입니다. 체코 어에서는 Windows 기본값을 사용합니다. (2020 년!) 콘솔 용 MS 비표준 852 (일명 Latin-2), Windows OEM으로서 1250, .NET (및 기타)으로서 UTF-8 (65001) 새로운 기본값이며 일부 서부 유럽 8 비트를 명심해야합니다. 데이터는 여전히 1252 년이지만 동유럽의 기존 8 비트 서부 표준은 ISO-8859-2 (일명 라틴 -2이지만 852와 같은 라틴 -2는 아님)입니다. ASCII를 사용한다는 것은 두부와 '?'로 가득 찬 텍스트를 의미합니다. 여기. 따라서 21 세기 반까지 UTF-8을 명시 적으로 설정하십시오 .


12

오프 구축 알리의 대답은 , 당신이 선택적으로 사용할 인코딩을 전달 할 수있는 확장 방법을 추천 할 것입니다 :

using System.Text;
public static class StringExtensions
{
    /// <summary>
    /// Creates a byte array from the string, using the 
    /// System.Text.Encoding.Default encoding unless another is specified.
    /// </summary>
    public static byte[] ToByteArray(this string str, Encoding encoding = Encoding.Default)
    {
        return encoding.GetBytes(str);
    }
}

그리고 아래와 같이 사용하십시오 :

string foo = "bla bla";

// default encoding
byte[] default = foo.ToByteArray();

// custom encoding
byte[] unicode = foo.ToByteArray(Encoding.Unicode);

2
다음을 사용 Encoding encoding = Encoding.Default하면 컴파일 시간 오류가 발생합니다.CS1736 Default parameter value for 'encoding' must be a compile-time constant
Douglas Gaskell

11

다음 접근법은 문자가 1 바이트 인 경우에만 작동합니다. (기본 유니 코드는 2 바이트이므로 작동하지 않습니다)

public static byte[] ToByteArray(string value)
{            
    char[] charArr = value.ToCharArray();
    byte[] bytes = new byte[charArr.Length];
    for (int i = 0; i < charArr.Length; i++)
    {
        byte current = Convert.ToByte(charArr[i]);
        bytes[i] = current;
    }

    return bytes;
}

단순하게 유지


charstringUTF-16에 의해 정의된다.
Tom Blodget

예, 기본값은 UTF-16입니다. 입력 문자열의 인코딩에 대해 가정하지 않습니다.
Mandar Sudame

인코딩 된 텍스트 외에 텍스트가 없습니다. 입력은 유형 string이므로 UTF-16입니다. UTF-16은 기본값이 아닙니다. 그것에 대한 선택의 여지가 없습니다. 그런 다음 char[]UTF-16 코드 단위 로 분할 합니다. 그런 다음 Convert.ToByte (Char) 를 호출 하면 U + 0000을 U + 00FF을 ISO-8859-1변환하고 다른 코드 포인트를 엉망으로 만듭니다.
Tom Blodget

맞는 말이다. 설명해 주셔서 감사합니다. 내 답변을 업데이트합니다.
Mandar Sudame

1
아직도 몇 가지 필수 사항이 누락 된 것 같습니다. char16 비트가되고 Convert.ToByte()반을 버리는 데 집중하십시오 .
Tom Blodget 1


6

JustinStolle의 편집 내용 수정 (Eran Yogev의 BlockCopy 사용).

제안 된 솔루션은 실제로 인코딩을 사용하는 것보다 빠릅니다. 문제는 길이가 고르지 않은 바이트 배열을 인코딩하는 데 작동하지 않는다는 것입니다. 주어진대로, 범위를 벗어난 예외가 발생합니다. 길이를 1 씩 늘리면 문자열에서 디코딩 할 때 후행 바이트가 남습니다.

나에게 인코딩해야 할 때가 필요 DataTable했습니다 JSON. 이진 필드를 문자열로 인코딩하고 문자열에서로 다시 디코딩하는 방법을 찾고있었습니다 byte[].

따라서 두 가지 클래스를 만들었습니다. 하나는 위의 솔루션을 래핑하는 것 (문자열에서 인코딩 할 때 길이는 항상 균일하므로)과 다른 하나는 byte[]인코딩 을 처리합니다 .

이진 배열의 원래 길이가 홀수 ( '1') 또는 짝수 ( '0')인지 알려주는 단일 문자를 추가하여 고르지 않은 길이 문제를 해결했습니다.

다음과 같이 :

public static class StringEncoder
{
    static byte[] EncodeToBytes(string str)
    {
        byte[] bytes = new byte[str.Length * sizeof(char)];
        System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
        return bytes;
    }
    static string DecodeToString(byte[] bytes)
    {
        char[] chars = new char[bytes.Length / sizeof(char)];
        System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
        return new string(chars);
    }
}

public static class BytesEncoder
{
    public static string EncodeToString(byte[] bytes)
    {
        bool even = (bytes.Length % 2 == 0);
        char[] chars = new char[1 + bytes.Length / sizeof(char) + (even ? 0 : 1)];
        chars[0] = (even ? '0' : '1');
        System.Buffer.BlockCopy(bytes, 0, chars, 2, bytes.Length);

        return new string(chars);
    }
    public static byte[] DecodeToBytes(string str)
    {
        bool even = str[0] == '0';
        byte[] bytes = new byte[(str.Length - 1) * sizeof(char) + (even ? 0 : -1)];
        char[] chars = str.ToCharArray();
        System.Buffer.BlockCopy(chars, 2, bytes, 0, bytes.Length);

        return bytes;
    }
}

4

이 질문은 여러 번 충분히 답변되었지만 C # 7.2와 Span 유형의 도입으로 안전하지 않은 코드에서 더 빠른 방법이 있습니다.

public static class StringSupport
{
    private static readonly int _charSize = sizeof(char);

    public static unsafe byte[] GetBytes(string str)
    {
        if (str == null) throw new ArgumentNullException(nameof(str));
        if (str.Length == 0) return new byte[0];

        fixed (char* p = str)
        {
            return new Span<byte>(p, str.Length * _charSize).ToArray();
        }
    }

    public static unsafe string GetString(byte[] bytes)
    {
        if (bytes == null) throw new ArgumentNullException(nameof(bytes));
        if (bytes.Length % _charSize != 0) throw new ArgumentException($"Invalid {nameof(bytes)} length");
        if (bytes.Length == 0) return string.Empty;

        fixed (byte* p = bytes)
        {
            return new string(new Span<char>(p, bytes.Length / _charSize));
        }
    }
}

바이트는 UTF-16으로 인코딩 된 문자열 (C # land에서 "Unicode"라고 함)을 나타냅니다.

일부 빠른 벤치마킹은 위의 메소드가 중간 크기 문자열 (30-50 문자)의 Encoding.Unicode.GetBytes (...) / GetString (...) 구현보다 약 5 배 빠르며 더 큰 문자열의 경우 훨씬 빠릅니다. 이 메소드는 Marshal.Copy (..) 또는 Buffer.MemoryCopy (...)와 함께 포인터를 사용하는 것보다 빠릅니다.


4

'searchResult.Properties [ "user"] [0]'의 결과가 문자열 인 경우 :

if ( ( searchResult.Properties [ "user" ].Count > 0 ) ) {

   profile.User = System.Text.Encoding.UTF8.GetString ( searchResult.Properties [ "user" ] [ 0 ].ToCharArray ().Select ( character => ( byte ) character ).ToArray () );

}

핵심은 LINQ를 사용하여 문자열을 바이트 []로 변환 할 수 있다는 것입니다.

.ToCharArray ().Select ( character => ( byte ) character ).ToArray () )

그리고 그 반대의 경우 :

.Select ( character => ( char ) character ).ToArray () )

3

아무도 이것을하지 않는 이유가 있습니까?

mystring.Select(Convert.ToByte).ToArray()

10
Convert.ToByte(char)생각대로 작동하지 않습니다. 문자 '2'는 문자 2를 나타내는 바이트가 아니라 바이트로 변환됩니다 '2'. mystring.Select(x => (byte)x).ToArray()대신 사용하십시오 .
Jack


2

MemoryMarshal API 를 사용하여 매우 빠르고 효율적인 변환을 수행 할 수 있습니다 . 또는 입력 매개 변수 를 허용 String하므로 암시 적으로에 캐스트됩니다 .ReadOnlySpan<byte>MemoryMarshal.CastSpan<byte>ReadOnlySpan<byte>

public static class StringExtensions
{
    public static byte[] ToByteArray(this string s) => s.ToByteSpan().ToArray(); //  heap allocation, use only when you cannot operate on spans
    public static ReadOnlySpan<byte> ToByteSpan(this string s) => MemoryMarshal.Cast<char, byte>(s);
}

다음 벤치 마크는 차이점을 보여줍니다.

Input: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s,"

|                       Method |       Mean |     Error |    StdDev |  Gen 0 | Gen 1 | Gen 2 | Allocated |
|----------------------------- |-----------:|----------:|----------:|-------:|------:|------:|----------:|
| UsingEncodingUnicodeGetBytes | 160.042 ns | 3.2864 ns | 6.4099 ns | 0.0780 |     - |     - |     328 B |
| UsingMemoryMarshalAndToArray |  31.977 ns | 0.7177 ns | 1.5753 ns | 0.0781 |     - |     - |     328 B |
|           UsingMemoryMarshal |   1.027 ns | 0.0565 ns | 0.1630 ns |      - |     - |     - |         - |

0

이 작업은 저에게 도움이됩니다. 그 후 데이터베이스의 bytea 필드에 그림을 넣을 수 있습니다.

using (MemoryStream s = new MemoryStream(DirEntry.Properties["thumbnailphoto"].Value as byte[]))
{
    return s.ToArray();
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.