C#中UTF-8 byte[]转string:哪种方法更快更好?

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

为什么“UTF-8 byte[]转string”这个问题经久不衰?



想象一下:你从网络请求中获取了一个字节数组,读取了一个二进制文件,或者从API反序列化了数据。里面是普通的俄语、英语或表情符号文本。但C#只看到了byte[]。你的任务是将这些0和1转换为可读的string字符串。



看起来很简单,对吧?调用一个方法就搞定了。但在Stack Overflow上,问题“How to convert UTF-8 byte[] to string”获得了数千次浏览和几十个回答。为什么?因为细节决定成败:编码、性能、安全性和意想不到的异常。



在本文中,我们不仅会提供现成的代码。我们将比较各种方法,测量速度,讨论潜在陷阱,并为每个任务选择最佳工具。如果你用C#编写代码并处理网络、文件或序列化——这篇文章就是为你准备的。



问题:byte[] 不是字符串



在C#中,string字符串以UTF-16编码存储。而你获得的字节很可能以UTF-8编码(互联网标准、JSON、大多数文本协议)。直接类型转换是不可能的——编译器会报错。



需要一个解码器,将UTF-8字节序列转换为UTF-16字符。有趣的部分从这里开始:开发者至少有三种截然不同的路径可以选择。



方法1:经典方法——Encoding.UTF8.GetString



最直接且微软推荐的方法是使用静态类System.Text.Encoding:



byte[] utf8Bytes = { 72, 101, 108, 108, 111, 32, 208, 191, 209, 128, 208, 176, 208, 178, 208, 176 }; // "Hello права"string result = Encoding.UTF8.GetString(utf8Bytes);Console.WriteLine(result); // 输出: Hello права


优点:

  • 简单——一行代码。
  • 支持所有编码,包括UTF-8、UTF-16、ASCII、Latin-1。
  • 内置BOM(字节顺序标记)处理——如果数组开头有UTF-8标记,它会被忽略。
  • 安全性——没有unsafe代码块。


缺点:

  • 每次调用都会创建一个新字符串和一个内部缓冲区。
  • 如果字节损坏或包含无效的UTF-8序列,默认情况下该方法会抛出DecoderFallbackException(除非配置了回退)。
  • 对于非常大的数组(数百兆字节)来说不是最优的——数据会被复制两次。


何时使用?

在95%的情况下使用。这是行业标准。如果你不是在编写高负载解析器或处理千兆字节的日志——请使用Encoding.UTF8.GetString。



方法2:快速且危险——使用指针的unsafe代码



适合追求速度且不畏惧unsafe的人。思路:我们知道UTF-8和UTF-16是不同的编码,但如果数组只包含ASCII字符(代码点小于127),则每个字节都可以“扩展”为2字节字符而无需解码。



unsafe string UnsafeAsciiBytesToString(byte[] bytes){    fixed (byte* pBytes = bytes)    {        return new string((sbyte*)pBytes, 0, bytes.Length);    }}


这段代码仅适用于ASCII!对于俄语文本(字符 > 127),结果将是乱码。但对于纯英语,它的速度比Encoding.UTF8.GetString快2-3倍。



优点:

  • 开销最小——没有复制,没有解码。
  • 非常适合解析HTTP头、JSON键(如果它们是ASCII)。


缺点:

  • 对多字节字符有风险——数据损坏。
  • 需要在项目中启用unsafe(并非所有环境都允许)。
  • 不处理

博客

书籍推荐