关于C#:如何将UTF-8转换为字符串?

How to convert UTF-8 byte[] to string?

我有一个byte[]数组,它是从一个我碰巧知道的包含utf-8的文件中加载的。在一些调试代码中,我需要将其转换为字符串。有没有一条航线可以做到这一点?

在封面之下,它应该只是一个分配和一个memcopy,所以即使它没有实现,它也应该是可能的。


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


至少有四种不同的转换方法。

  • encoding的getstring
    ,但是如果这些字节具有非ASCII字符,则无法返回原始字节。

  • bitconverter.toString
    输出是以"-"分隔的字符串,但没有.NET内置方法将字符串转换回字节数组。

  • convert.tobase64string
    使用Convert.FromBase64String可以很容易地将输出字符串转换回字节数组。
    注意:输出字符串可以包含"+"、"/"和"="。如果要在URL中使用该字符串,则需要显式地对其进行编码。

  • httpserverputility.urltokenencode
    使用HttpServerUtility.UrlTokenDecode可以轻松地将输出字符串转换回字节数组。输出字符串已经是URL友好的!缺点是,如果您的项目不是Web项目,它需要System.Web程序集。

  • 一个完整的例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    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


    不知道编码时从字节数组转换为字符串的一般解决方案:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    static string BytesToStringConverted(byte[] bytes)
    {
        using (var stream = new MemoryStream(bytes))
        {
            using (var streamReader = new StreamReader(stream))
            {
                return streamReader.ReadToEnd();
            }
        }
    }


    定义:

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

    使用:

    1
    string result = input.ConvertByteToString();

    byte[]转换为string似乎很简单,但任何类型的编码都可能会破坏输出字符串。这个小函数工作时没有任何意外结果:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    private string ToString(byte[] bytes)
    {
        string response = string.Empty;

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

        return response;
    }


    使用(byte)b.ToString("x2")输出b4b5dfe475e58b67

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    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;
        }

    }


    还有类unicodeencoding,使用起来很简单:

    1
    2
    3
    4
    5
    ByteConverter = new UnicodeEncoding();
    string stringDataForEncoding ="My&nbsp;Secret&nbsp;Data!";
    byte[] dataEncoded = ByteConverter.GetBytes(stringDataForEncoding);

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


    据我所知,任何给定的答案都不能保证正确的行为和无效的终止。在有人以不同的方式向我展示之前,我用以下方法编写了自己的静态类来处理这个问题:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    // 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[]解析为以空结尾的字符串数组。在简单的情况下可以安全地忽略它


    BitConverter类可用于将byte[]转换为string

    1
    var convertedString = BitConverter.ToString(byteAttay);

    BitConverter类文件可在msdn上找到。


    用于将从文件中读取的字节数组byteArrFilename转换为纯ASCII C样式的以零结尾的字符串的LINQ ONE行程序是这样的:对于以旧的存档格式读取文件索引表之类的内容很方便。

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

    我在这里使用'?'作为任何非纯ASCII字符的默认字符,当然,这是可以更改的。如果您想确定可以检测到它,只需使用'\0',因为开始时的TakeWhile确保以这种方式构建的字符串不可能包含来自输入源的'\0'值。


    可选地:

    1
     var byteStr = Convert.ToBase64String(bytes);


    Hier是一种不用费心编码的结果。我在网络类中使用它,并将二进制对象作为字符串发送。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
            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);
            }


    根据所选答案,如果使用.net35或.net35 ce,则必须指定要解码的第一个字节的索引和要解码的字节数:

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

    试试这个:

    1
    string myresult = System.Text.Encoding.UTF8.GetString(byteArray);