C# 从 UTF-8 流中读取字符串的正确方法及代码详解

 更新时间:2021年11月22日 08:28:24   作者:wanghao72214  
在本篇文章里小编给大家整理的是一篇关于C# 从 UTF-8 流中读取字符串的正确方法的知识点内容,有兴趣的朋友们可以学习参考下。

 我们下面的代码是从一个流 stream 中读取 UTF-8 编码的字符串。我们可以先考虑一下其中存在的潜在问题。

string ReadString(Stream stream)
{
    var sb = new StringBuilder();
    var buffer = new byte[4096];
    int readCount;
    while ((readCount = stream.Read(buffer)) > 0)
    {
        var s = Encoding.UTF8.GetString(buffer, 0, readCount);
        sb.Append(s);
    }

    return sb.ToString();
}

问题出在:某些情况下返回的字符串与与原始编码的字符串并不同。

例如,笑脸符号😊 有时会被解码为 4 个未知字符:

编码字符串: 😊
解码字符串: ????

我们知道:UTF-8 可以使用 1 到 4 个字节来表示一个 Unicode 字符,有关字符串编码的知识可以参考 ​​字符编码​​​ 一文。

​​Stream.Read​​​ 方法可以把从 1 到​​ messageBuffer.Length​​​ 字节返回,这意味着缓冲区可能包含不完整的 UTF-8 字符。

一旦缓冲区中的最后一个字符的 UTF-8 编码不完整,那么 ​​Encoding.UTF8.GetString​​ 就是转换一个无效的 UTF-8 字符串。在这种情况下,该方法返回一个无效字符串,因为它无法猜测丢失的字节。

我们使用以下代码演示以上行为:

var bytes = Encoding.UTF8.GetBytes("?");
// bytes = new byte[4] { 240, 159, 152, 138 }

var sb = new StringBuilder();
// 模拟逐个字节地读取数据流
for (var i = 0; i < bytes.Length; i++)
{
    sb.Append(Encoding.UTF8.GetString(bytes, i, 1));
}

Console.WriteLine(sb.ToString());
// "????" 代替了 "😊"

Encoding.UTF8.GetBytes(sb.ToString());
// new byte[12] { 239, 191, 189, 239, 191, 189, 239, 191, 189, 239, 191, 189 }

如何修复代码

有多种方法可以修复代码。

第一种方法:只有当你得到全部数据时,才将字节数组转换为字符串。

string ReadString(Stream stream)
{
    using var ms = new MemoryStream();
    var buffer = new byte[4096];
    int readCount;
    while ((readCount = stream.Read(buffer)) > 0)
    {
        ms.Write(buffer, 0, readCount);
    }

    return Encoding.UTF8.GetString(ms.ToArray());
}

第二种方法:可以把流包进一个具有正确编码的 StreamReader 对象中。

string ReadString(Stream stream)
{
    using var sr = new StreamReader(stream, Encoding.UTF8);
    return sr.ReadToEnd();
}

另外,还可以使用System.Text.Decoder类来正确解码缓冲区内的字符。在需要性能的情况下,可以使用PipeReader、Rune类来以内存优化的方式读取数据。

到此这篇关于C# 从 UTF-8 流中读取字符串的正确方法及代码详解的文章就介绍到这了,更多相关C# 从 UTF-8 流中读取字符串的正确方法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 浅析C#中StringBuilder类的高效及与String的对比

    浅析C#中StringBuilder类的高效及与String的对比

    StringBuilder类所创造出来的字符串对象在拼接操作等方面比普通的string类往往要高效很多,这是它们在内存划分方式上的不同所决定的,下面就来浅析C#中StringBuilder类的高效及与String的对比
    2016-05-05
  • 使用C#连接并读取MongoDB数据库

    使用C#连接并读取MongoDB数据库

    这篇文章介绍了使用C#连接并读取MongoDB数据库的方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-03-03
  • C#简单实现发送socket字符串

    C#简单实现发送socket字符串

    这篇文章主要为大家详细介绍了C#简单实现socket字符串发送,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-09-09
  • C# 控件属性和InitializeComponent()关系案例详解

    C# 控件属性和InitializeComponent()关系案例详解

    这篇文章主要介绍了C# 控件属性和InitializeComponent()关系案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08
  • C# 在PDF文档中创建表格的实现方法

    C# 在PDF文档中创建表格的实现方法

    表格能够一目了然的让用户看到数据信息,使信息显得有条理化,那么在pdf类型的文档中如何来添加表格并对表格进行格式化操作呢?下面小编给大家带来了C# 在PDF文档中创建表格的实现方法,需要的朋友参考下吧
    2017-12-12
  • c# winform多线程死循环踩坑

    c# winform多线程死循环踩坑

    本文主要介绍了c# winform多线程死循环踩坑,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-12-12
  • C#实现窗体全屏的两种方法

    C#实现窗体全屏的两种方法

    这篇文章主要为大家详细介绍了C#实现窗体全屏的两种方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-10-10
  • c#使用UTF-8编码实现处理多语言文本

    c#使用UTF-8编码实现处理多语言文本

    UTF-8编码是现代应用中处理多语言文本的首选,所以本文为大家详细介绍了C#如何使用UTF-8编码实现处理多语言文本,感兴趣的小伙伴可以了解下
    2024-01-01
  • C#中调用Windows API的技术要点说明

    C#中调用Windows API的技术要点说明

    本篇文章主要是对C#中调用Windows API的技术要点进行了详细的介绍,需要的朋友可以过来参考下,希望对大家有所帮助
    2014-01-01
  • C#使用Thrift作为RPC框架入门详细教程

    C#使用Thrift作为RPC框架入门详细教程

    这篇文件我们讲了从0到1使用thrift框架的方法,也讲了一些该框架的基本知识,本文将详细介绍 Thrift 在C#语言下的使用方式,并且提供丰富的实例代码加以解释说明,帮助使用者快速构建服务,感兴趣的朋友一起看看吧
    2021-11-11

最新评论