Как преобразовать UTF-8 byte [] в строку?

805

У меня есть массив byte[], который загружается из файла, который, как мне известно, содержит UTF-8. В некотором отладочном коде мне нужно преобразовать его в строку. Есть ли один лайнер, который сделает это?

Под обложками это должно быть просто распределение и memcopy, поэтому даже если он не реализован, это должно быть возможно.

  • 4
    «должно быть просто выделением и записью»: неверно, потому что строка .NET имеет кодировку UTF-16. Символ Unicode может быть одной кодовой единицей UTF-8 или одной кодовой единицей UTF-16. другая может быть двумя кодовыми единицами UTF-8 или одной кодовой единицей UTF-16, другая может быть тремя кодовыми единицами UTF-8 или одной кодовой единицей UTF-16, другая может быть четырьмя кодовыми единицами UTF-8 или двумя кодовыми единицами UTF-16 , Memcopy может быть в состоянии расширить, но он не сможет обрабатывать преобразования UTF-8 в UTF-16.
Теги:
string
arrays
type-conversion

14 ответов

1349
Лучший ответ
string result = System.Text.Encoding.UTF8.GetString(byteArray);
  • 13
    как он обрабатывает строки с нулевым окончанием?
  • 12
    @maazza по неизвестной причине это не так вообще. Я называю это как System.Text.Encoding.UTF8.GetString(buf).TrimEnd('\0'); ,
Показать ещё 6 комментариев
276

По крайней мере четыре разных способа выполнения этого преобразования.

  • Encoding GetString
    , но вы не сможете вернуть исходные байты, если эти байты имеют символы, отличные от ASCII.

  • BitConverter.ToString
    Вывод представляет собой строку с разделителями" -", но нет встроенного метода .NET для преобразования строки обратно в массив байтов.

  • Convert.ToBase64String
    Вы можете легко преобразовать выходную строку обратно в массив байтов, используя Convert.FromBase64String.
    Примечание. Выходная строка может содержать '+ ','/'и' = '. Если вы хотите использовать строку в URL-адресе, вам необходимо явно закодировать ее.

  • HttpServerUtility.UrlTokenEncode
    Вы можете легко преобразовать выходную строку обратно в массив байтов, используя HttpServerUtility.UrlTokenDecode. Строка вывода уже удобна для URL! Недостатком является необходимость сборки System.Web, если ваш проект не является веб-проектом.

Полный пример:

byte[] bytes = { 130, 200, 234, 23 }; // A byte array contains non-ASCII (or non-readable) characters

string s1 = Encoding.UTF8.GetString(bytes); // ���
byte[] decBytes1 = Encoding.UTF8.GetBytes(s1);  // decBytes1.Length == 10 !!
// decBytes1 not same as bytes
// Using UTF-8 or other Encoding object will get similar results

string s2 = BitConverter.ToString(bytes);   // 82-C8-EA-17
String[] tempAry = s2.Split('-');
byte[] decBytes2 = new byte[tempAry.Length];
for (int i = 0; i < tempAry.Length; i++)
    decBytes2[i] = Convert.ToByte(tempAry[i], 16);
// decBytes2 same as bytes

string s3 = Convert.ToBase64String(bytes);  // gsjqFw==
byte[] decByte3 = Convert.FromBase64String(s3);
// decByte3 same as bytes

string s4 = HttpServerUtility.UrlTokenEncode(bytes);    // gsjqFw2
byte[] decBytes4 = HttpServerUtility.UrlTokenDecode(s4);
// decBytes4 same as bytes
  • 4
    LINQ it: var decBytes2 = str.Split('-').Select(ch => Convert.ToByte(ch, 16)).ToArray();
21

Общее решение для преобразования из байтового массива в строку, когда вы не знаете кодировку:

static string BytesToStringConverted(byte[] bytes)
{
    using (var stream = new MemoryStream(bytes))
    {
        using (var streamReader = new StreamReader(stream))
        {
            return streamReader.ReadToEnd();
        }
    }
}
  • 1
    Но это предполагает, что в байтовом потоке есть либо кодирующая спецификация, либо что она находится в UTF-8. Но вы можете сделать то же самое с кодировкой в любом случае. Это волшебным образом не решает проблему, когда вы не знаете кодировку.
12

Определение:

public static string ConvertByteToString(this byte[] source)
{
    return source != null ? System.Text.Encoding.UTF8.GetString(source) : null;
}

Использование:

string result = input.ConvertByteToString();
9

Преобразование a byte[] в string кажется простым, но любое кодирование может испортить выходную строку. Эта небольшая функция работает без каких-либо неожиданных результатов:

private string ToString(byte[] bytes)
{
    string response = string.Empty;

    foreach (byte b in bytes)
        response += (Char)b;

    return response;
}
  • 0
    Я получил System.FormatException, используя ваш метод, когда распаковал его с Convert.FromBase64String.
  • 0
    @ AndrewJE это займет даже для вычисления, если у вас есть большой массив байтов, как тот, который используется на рисунках.
8

Используя (byte)b.ToString("x2"), выходы b4b5dfe475e58b67

public static class Ext {

    public static string ToHexString(this byte[] hex)
    {
        if (hex == null) return null;
        if (hex.Length == 0) return string.Empty;

        var s = new StringBuilder();
        foreach (byte b in hex) {
            s.Append(b.ToString("x2"));
        }
        return s.ToString();
    }

    public static byte[] ToHexBytes(this string hex)
    {
        if (hex == null) return null;
        if (hex.Length == 0) return new byte[0];

        int l = hex.Length / 2;
        var b = new byte[l];
        for (int i = 0; i < l; ++i) {
            b[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16);
        }
        return b;
    }

    public static bool EqualsTo(this byte[] bytes, byte[] bytesToCompare)
    {
        if (bytes == null && bytesToCompare == null) return true; // ?
        if (bytes == null || bytesToCompare == null) return false;
        if (object.ReferenceEquals(bytes, bytesToCompare)) return true;

        if (bytes.Length != bytesToCompare.Length) return false;

        for (int i = 0; i < bytes.Length; ++i) {
            if (bytes[i] != bytesToCompare[i]) return false;
        }
        return true;
    }

}
5

Существует также класс UnicodeEncoding, довольно простой в использовании:

ByteConverter = new UnicodeEncoding();
string stringDataForEncoding = "My Secret Data!";
byte[] dataEncoded = ByteConverter.GetBytes(stringDataForEncoding);

Console.WriteLine("Data after decoding: {0}", ByteConverter.GetString(dataEncoded));
  • 0
    Но не UTF-8 метинкс?
  • 0
    UnicodeEncoding - худшее имя класса в мире; Юникод вообще не является кодировкой. Этот класс на самом деле UTF-16. Версия с прямым порядком байтов, я думаю.
2

Насколько мне известно, ни один из данных ответов не гарантирует правильное поведение с нулевым завершением. Пока кто-то не показывает меня по-другому, я написал свой собственный статический класс для обработки этого с помощью следующих методов:

// Mimics the functionality of strlen() in c/c++
// Needed because niether StringBuilder or Encoding.*.GetString() handle \0 well
static int StringLength(byte[] buffer, int startIndex = 0)
{
    int strlen = 0;
    while
    (
        (startIndex + strlen + 1) < buffer.Length // Make sure incrementing won't break any bounds
        && buffer[startIndex + strlen] != 0       // The typical null terimation check
    )
    {
        ++strlen;
    }
    return strlen;
}

// This is messy, but I haven't found a built-in way in c# that guarentees null termination
public static string ParseBytes(byte[] buffer, out int strlen, int startIndex = 0)
{
    strlen = StringLength(buffer, startIndex);
    byte[] c_str = new byte[strlen];
    Array.Copy(buffer, startIndex, c_str, 0, strlen);
    return Encoding.UTF8.GetString(c_str);
}

Причина для startIndex была в примере, в котором я работал специально, мне нужно было проанализировать byte[] как массив строк с нулевым завершением. Его можно безопасно игнорировать в простом случае

  • 0
    Мой, на самом деле. byteArr.TakeWhile(x => x != 0) - это быстрый и простой способ решения проблемы нулевого завершения.
2

BitConverter класс может использоваться для преобразования byte[] в string.

var convertedString = BitConverter.ToString(byteAttay);

Документация класса BitConverter может быть установлена ​​на MSDN

2

Однострочный Linq для преобразования байтового массива byteArrFilename, считанный из файла, в строку с нулевым завершающим строком в стиле ascii C-style будет следующим: Handy для чтения таких вещей, как таблицы индексных файлов в старых архивных форматах.

String filename = new String(byteArrFilename.TakeWhile(x => x != 0)
                              .Select(x => x < 128 ? (Char)x : '?').ToArray());

Я использую '?' по умолчанию char для чего-то не чистого ascii здесь, но это может быть изменено, конечно. Если вы хотите убедиться, что можете его обнаружить, просто используйте '\0' вместо этого, так как TakeWhile в начале гарантирует, что строка, построенная таким образом, не может содержать значения '\0' из источника ввода.

2

В качестве альтернативы:

 var byteStr = Convert.ToBase64String(bytes);
0

В дополнение к выбранному ответу, если вы все еще используете .NET35 или .NET35 CE, вы должны указать индекс первого байта для декодирования и количество байтов для декодирования:

string result = System.Text.Encoding.UTF8.GetString(byteArray,0,byteArray.Length);
0

hier - результат, когда вам не пришлось беспокоиться о кодировании. Я использовал его в своем сетевом классе и отправлял ему двоичные объекты.

        public static byte[] String2ByteArray(string str)
        {
            char[] chars = str.ToArray();
            byte[] bytes = new byte[chars.Length * 2];

            for (int i = 0; i < chars.Length; i++)
                Array.Copy(BitConverter.GetBytes(chars[i]), 0, bytes, i * 2, 2);

            return bytes;
        }

        public static string ByteArray2String(byte[] bytes)
        {
            char[] chars = new char[bytes.Length / 2];

            for (int i = 0; i < chars.Length; i++)
                chars[i] = BitConverter.ToChar(bytes, i * 2);

            return new string(chars);
        }
  • 0
    Где твой юнит тест;)?
  • 0
    не было одного. Но эта функция используется для двоичной передачи в нашей корпоративной сети, и до сих пор 20 ТБ были правильно и повторно закодированы. Так что для меня эта функция работает :)
0

Попробуй это:

string myresult = System.Text.Encoding.UTF8.GetString(byteArray);
Сообщество Overcoder
Наверх
Меню