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 流中读取字符串的正确方法的更多相关文章
- Python从文件中读取字符串,用正则表达式匹配中文字符的问题
2013-07-27 21:01:37| 在Windows下,用Python从.txt文件中读取字符串,并用正则表达式匹配中文,在网上看了方法,用的时候发现中文没有被匹配. ...
- nodeks —— fs模块 —— 从流中 读取和写入数据
Fs流读取和写入数据 使用文件流来读取大文件不会卡顿 1, 从流中读取数据 var fs = require("fs"); var data = ''; var count = 0 ...
- Python3实现从文件中读取指定行的方法
from:http://www.jb51.net/article/66580.htm 这篇文章主要介绍了Python3实现从文件中读取指定行的方法,涉及Python中linecache模块操作文件的使 ...
- php中读取大文件实现方法详解
php中读取大文件实现方法详解 来源: 时间:2013-09-05 19:27:01 阅读数:6186 分享到:0 [导读] 本文章来给各位同学介绍php中读取大文件实现方法详解吧,有需要了解 ...
- 归纳从文件中读取数据的六种方法-JAVA IO基础总结第2篇
在上一篇文章中,我为大家介绍了<5种创建文件并写入文件数据的方法>,本节我们为大家来介绍6种从文件中读取数据的方法. 另外为了方便大家理解,我为这一篇文章录制了对应的视频:总结java从文 ...
- R中读取EXCEL 数据的方法
最近初学R语言,在R语言读入EXCEL数据格式文件的问题上遇到了困难,经过在网上搜索解决了这一问题,下面归纳几种方法,供大家分享: 第一:R中读取excel文件中的数据的路径: 假定在您的电脑有一个e ...
- 利用Python从文件中读取字符串(解决乱码问题)
首先声明这篇学习记录是基于python3的. python3中,py文件中默认的文件编码就是unicode,不用像python2中那样加u,比如u'中文'. 不过在涉及路径时,比如C:\Users\A ...
- Java从内存流中读取byte数组
Java中通过servlet接收二进制数据,然后将二进制数据流读取为byte数组.开始使用:byte[] bs = new byte[request.getContentLength()];reque ...
- java中读取资源文件的方法
展开全部 1.使用java.util.Properties类的load()方法 示例: //文件在项目下.不是在包下!! InputStream in = new BufferedInputStrea ...
随机推荐
- Dart 中的final 和 const
Dart 常量和常量值 final 和 const 两个关键字用来定义常量,有什么区别呢? final 声明的是运行时常量,const声明的是编译时常量 const 可以声明常量值 举个例子: imp ...
- 飞猪基于 Serverless 的云+端实践与思考
作者 | 王恒飞(承荫) 本文整理自飞猪旅行前端技术专家--王恒飞(承荫)在[阿里云 Serverless Developer Meetup 上海站]上的分享.点击查看直播回放:https://dev ...
- Vulnhub实战-DockHole_1靶机👻
Vulnhub实战-DockHole_1靶机 靶机地址:https://www.vulnhub.com/entry/darkhole-1,724/ 1.描述 我们下载下来这个靶机然后在vmware中打 ...
- 使用mobaXtrem显示CentOS图形
安装环境 yum install -y xorg-x11-xauth xorg-x11-fonts-* xorg-x11-font-utils xorg-x11-fonts-Type1 \mesa-l ...
- 一个小众搞笑的xss漏洞练习平台
XSS是当今网络安全事件中数量最多的攻击方式,虽然其危害性不高,但主要和其他攻击手段相结合,以实现一个复杂的攻击场景.那么,XSS是什么? XSS全称跨站脚本(Cross Site Scripting ...
- DL4J实战之五:矩阵操作基本功
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...
- 【Spring】IoC容器 - 依赖来源
前言 上一篇文章已经学习了[依赖注入]相关的知识,这里详细的介绍一下[依赖来源]. 依赖来源 我们把依赖来源分为依赖查找的来源和依赖注入的来源分别讨论. 依赖查找的来源 1. Spring BeanD ...
- 【数据结构与算法Python版学习笔记】算法分析
什么是算法分析 算法是问题解决的通用的分步的指令的聚合 算法分析主要就是从计算资源的消耗的角度来评判和比较算法. 计算资源指标 存储空间或内存 执行时间 影响算法运行时间的其他因素 分为最好.最差和平 ...
- SpringCloud微服务实战——搭建企业级开发框架(六):使用knife4j集成Swagger2接口文档
knife4j是为集成Swagger生成api文档的增强解决方案,前后端Java代码以及前端Ui模块进行分离,在微服务架构下使用更加灵活, 提供专注于Swagger的增强解决方案,不同于只是改善增强前 ...
- 【Deeplearning.ai 】吴恩达深度学习笔记及课后作业目录
吴恩达深度学习课程的课堂笔记以及课后作业 代码下载:https://github.com/douzujun/Deep-Learning-Coursera 吴恩达推荐笔记:https://mp.weix ...