Làm cách nào để chuyển đổi UTF-8 byte [] thành chuỗi?


932

Tôi có một byte[]mảng được tải từ một tệp mà tôi biết có chứa UTF-8 .

Trong một số mã gỡ lỗi, tôi cần chuyển đổi nó thành một chuỗi. Có một lót sẽ làm điều này?

Dưới sự bao trùm nó phải được chỉ là một phân bổ và memcopy , vì vậy ngay cả khi nó không được thực hiện, nó phải là tốt.


5
"nên chỉ là phân bổ và ghi nhớ": không đúng vì chuỗi .NET được mã hóa UTF-16. Một ký tự Unicode có thể là một đơn vị mã UTF-8 hoặc một đơn vị mã UTF-16. một đơn vị khác có thể là hai đơn vị mã UTF-8 hoặc một đơn vị mã UTF-16, đơn vị khác có thể là ba đơn vị mã UTF-8 hoặc một đơn vị mã UTF-16, đơn vị khác có thể là bốn đơn vị mã UTF-8 hoặc hai đơn vị mã UTF-16 . Một bản ghi nhớ có thể mở rộng nhưng nó sẽ không thể xử lý chuyển đổi UTF-8 sang UTF-16.
Tom Blodget

Câu trả lời:


1470
string result = System.Text.Encoding.UTF8.GetString(byteArray);

13
Làm thế nào để nó xử lý chuỗi kết thúc null?
maazza

14
@maazza không rõ lý do. Tôi đang gọi nó như thế System.Text.Encoding.UTF8.GetString(buf).TrimEnd('\0');.
Hi-Angel

15
@ Hi-Angel Không rõ lý do? Lý do duy nhất khiến các chuỗi kết thúc null trở nên phổ biến là ngôn ngữ C - và thậm chí đó chỉ là do sự kỳ lạ trong lịch sử (các lệnh CPU xử lý các chuỗi kết thúc null). .NET chỉ sử dụng các chuỗi kết thúc null khi xen kẽ với mã sử dụng các chuỗi kết thúc null ( cuối cùng biến mất). Nó hoàn toàn hợp lệ cho một chuỗi chứa các ký tự NUL. Và tất nhiên, trong khi các chuỗi kết thúc null là đơn giản trong ASCII (chỉ cần xây dựng cho đến khi bạn nhận được byte 0 đầu tiên), các mã hóa khác, bao gồm UTF-8, không đơn giản như vậy.
Luaan

4
Một trong những tính năng hay của UTF-8 là một chuỗi ngắn hơn không bao giờ là một chuỗi dài hơn. Vì vậy, một chuỗi UTF-8 kết thúc null là đơn giản.
cắm vào

10
Chà, chúc may mắn giải nén nó nếu nó không có ascii. Chỉ cần sử dụng Convert.ToBase64String.
Erik Bergstedt

323

Có ít nhất bốn cách khác nhau để thực hiện chuyển đổi này.

  1. Mã hóa GetString
    , nhưng bạn sẽ không thể lấy lại các byte gốc nếu các byte đó có các ký tự không phải ASCII.

  2. BitConverter.ToString
    Đầu ra là một chuỗi được phân tách bằng "-", nhưng không có phương thức tích hợp .NET để chuyển đổi chuỗi trở lại mảng byte.

  3. Convert.ToBase64String
    Bạn có thể dễ dàng chuyển đổi chuỗi đầu ra trở lại mảng byte bằng cách sử dụng Convert.FromBase64String.
    Lưu ý: Chuỗi đầu ra có thể chứa '+', '/' và '='. Nếu bạn muốn sử dụng chuỗi trong một URL, bạn cần mã hóa rõ ràng.

  4. HttpServerUtility.UrlTokenEncode
    Bạn có thể dễ dàng chuyển đổi chuỗi đầu ra trở lại mảng byte bằng cách sử dụng HttpServerUtility.UrlTokenDecode. Chuỗi đầu ra đã thân thiện với URL! Nhược điểm là nó cần System.Weblắp ráp nếu dự án của bạn không phải là một dự án web.

Một ví dụ đầy đủ:

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

7
LINQ nó:var decBytes2 = str.Split('-').Select(ch => Convert.ToByte(ch, 16)).ToArray();
drtf

25

Một giải pháp chung để chuyển đổi từ mảng byte thành chuỗi khi bạn không biết mã hóa:

static string BytesToStringConverted(byte[] bytes)
{
    using (var stream = new MemoryStream(bytes))
    {
        using (var streamReader = new StreamReader(stream))
        {
            return streamReader.ReadToEnd();
        }
    }
}

3
Nhưng điều này giả định rằng có một BOM mã hóa trong luồng byte hoặc nó nằm trong UTF-8. Nhưng dù sao bạn cũng có thể làm tương tự với Encoding. Nó không giải quyết được vấn đề một cách kỳ diệu khi bạn không biết mã hóa.
Sebastian Zander

12

Định nghĩa:

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

Sử dụng:

string result = input.ConvertByteToString();

9

Chuyển đổi một byte[]đến một stringvẻ đơn giản nhưng bất kỳ loại mã hóa có thể gặp rắc rối với chuỗi đầu ra. Chức năng nhỏ này chỉ hoạt động mà không có kết quả bất ngờ:

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

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

    return response;
}

Tôi đã nhận được System.FormatException bằng phương thức của bạn khi tôi giải nén nó bằng Convert.FromBase64String.
Erik Bergstedt

@ AndrewJE điều này sẽ mất ngay cả để tính toán nếu bạn có một mảng byte lớn giống như mảng được sử dụng từ các hình ảnh.
dùng3841581

7

Sử dụng (byte)b.ToString("x2"), đầu rab4b5dfe475e58b67

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

}

4

Ngoài ra còn có lớp UnicodeEncoding, cách sử dụng khá đơn giản:

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

Console.WriteLine("Data after decoding: {0}", ByteConverter.GetString(dataEncoded));

Nhưng không phải là UTF-8 methinks?
david.pfx 14/07/2015

1
UnicodeEncodinglà tên lớp tồi tệ nhất từ ​​trước đến nay; unicode hoàn toàn không phải là mã hóa. Lớp đó thực sự là UTF-16. Phiên bản nhỏ về cuối, tôi nghĩ vậy.
Nyerguds

3

Cách khác:

 var byteStr = Convert.ToBase64String(bytes);

2

Một Linq one-liner để chuyển đổi một mảng byte byteArrFilenameđược đọc từ một tệp thành một chuỗi kết thúc bằng 0 kiểu ascii thuần túy sẽ là: Tiện dụng để đọc những thứ như bảng chỉ mục tệp ở các định dạng lưu trữ cũ.

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

Tôi sử dụng '?'như char mặc định cho bất cứ thứ gì không phải là ascii thuần túy ở đây, nhưng điều đó có thể được thay đổi, tất nhiên. Nếu bạn muốn chắc chắn rằng bạn có thể phát hiện ra nó, chỉ cần sử dụng '\0'thay thế, vì khi TakeWhilebắt đầu, đảm bảo rằng một chuỗi được xây dựng theo cách này không thể chứa '\0'các giá trị từ nguồn đầu vào.


2

BitConverterlớp có thể được sử dụng để chuyển đổi một byte[]để string.

var convertedString = BitConverter.ToString(byteAttay);

Tài liệu về BitConverterlớp học có thể được cập nhật trên MSDN


1
Điều này chuyển đổi mảng byte thành một chuỗi thập lục phân đại diện cho mỗi byte, thường không phải là những gì bạn muốn khi chuyển đổi byte thành một chuỗi. Nếu bạn làm vậy, thì đó là một câu hỏi khác, xem ví dụ: Làm thế nào để bạn chuyển đổi Byte Array thành Chuỗi thập lục phân và ngược lại? .
CodeCaster

Không phải những gì OP yêu cầu
Mùa đông

2

Theo hiểu biết của tôi, không có câu trả lời nào được đưa ra đảm bảo hành vi đúng với chấm dứt null. Cho đến khi ai đó chỉ cho tôi khác đi, tôi đã viết lớp tĩnh của riêng mình để xử lý việc này bằng các phương thức sau:

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

Lý do startIndexlà trong ví dụ tôi đang làm việc cụ thể tôi cần phân tích cú pháp byte[]dưới dạng một chuỗi các chuỗi kết thúc null. Nó có thể được bỏ qua một cách an toàn trong trường hợp đơn giản


Của tôi, thực sự. byteArr.TakeWhile(x => x != 0)là một cách nhanh chóng và dễ dàng để giải quyết vấn đề chấm dứt null.
Nyerguds

1

hier là kết quả mà bạn không phải bận tâm với mã hóa. Tôi đã sử dụng nó trong lớp mạng của mình và gửi các đối tượng nhị phân dưới dạng chuỗi với nó.

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

không có một cái. Nhưng chức năng này được sử dụng để truyền nhị phân trong mạng công ty của chúng tôi và cho đến nay 20TB đã được mã hóa lại và chính xác. Vì vậy, đối với tôi chức năng này hoạt động :)
Marco Pardo

1

Để trả lời cho câu trả lời đã chọn, nếu bạn đang sử dụng .NET35 hoặc .NET35 CE, bạn phải chỉ định chỉ số của byte đầu tiên để giải mã và số byte để giải mã:

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

0

Hãy thử ứng dụng bảng điều khiển này:

static void Main(string[] args)
{
    //Encoding _UTF8 = Encoding.UTF8;
    string[] _mainString = { "Héllo World" };
    Console.WriteLine("Main String: " + _mainString);

    //Convert a string to utf-8 bytes.
    byte[] _utf8Bytes = Encoding.UTF8.GetBytes(_mainString[0]);

    //Convert utf-8 bytes to a string.
    string _stringuUnicode = Encoding.UTF8.GetString(_utf8Bytes);
    Console.WriteLine("String Unicode: " + _stringuUnicode);
}

0

Tôi đã thấy một số câu trả lời tại bài đăng này và có thể được coi là kiến ​​thức cơ bản đã hoàn thành, bởi vì có một số cách tiếp cận trong Lập trình C # để giải quyết vấn đề tương tự. Chỉ có một điều cần được xem xét là về sự khác biệt giữa Pure UTF-8UTF-8 với BOM .

Trong tuần trước, trong công việc của mình, tôi cần phát triển một chức năng xuất các tệp CSV bằng BOM và các CSV khác bằng UTF-8 thuần túy (không có BOM), mỗi loại Mã hóa tệp CSV sẽ được sử dụng bởi các API không được chuẩn hóa khác nhau, đó là một API API đọc UTF-8 với BOM và API khác đọc mà không có BOM. Tôi cần nghiên cứu các tài liệu tham khảo về khái niệm này, đọc " Sự khác biệt giữa UTF-8 và UTF-8 không có BOM là gì? " Thảo luận về Stack Overflow và Wikipedia này liên kết " Dấu thứ tự byte " để xây dựng phương pháp của tôi.

Cuối cùng, Lập trình C # của tôi cho cả hai loại mã hóa UTF-8 (với BOM và thuần túy) cần phải giống như ví dụ dưới đây:

//for UTF-8 with B.O.M., equals shared by Zanoni (at top)
string result = System.Text.Encoding.UTF8.GetString(byteArray);

//for Pure UTF-8 (without B.O.M.)
string result = (new UTF8Encoding(false)).GetString(byteArray);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.