Stream.Write 与 StreamWriter.Write 的区别
Stream.Write 与 StreamWriter.Write 是我们在向流中写数据时,最常用的方法。下面就详细讲解这两个方法。
一、测试方法是否结果相同
首先看下面两段代码左侧是StreamWriter.Write 右侧是Stream.Write:
1 2 3 4 5 6 | Stream ms = new MemoryStream(); string str = "这是测试字符串" ; StreamWriter sw = new StreamWriter(ms, Encoding.UTF8); sw.Write(str); sw.Flush(); |
1 2 3 4 5 6 | Stream ms = new MemoryStream(); string str = "这是测试字符串" ; byte [] buffer = Encoding.UTF8.GetBytes(str); ms.Write(buffer, 0, buffer.Length); ms.Flush(); |
上面我们可以看到StreamWriter.Write的可读性更好一些。
但是这两段代码执行后的ms是否是相同的结果呢?
首先我们来看下长度吧,在代码最后分别加上
1 2 | Console.WriteLine( "StreamWriter.Write:{0}" , ms.Length); Console.WriteLine( "Stream.Write:{0}" , ms.Length); |
执行后结果如下:
各位看官,看到这里有何想法?
二、深究原因
下面继续深究一下这个多出来的3个字节
在方法后面都加上如下一段代码将MemoryStream的内容以十六进制的形式打印出来
1 2 3 4 5 6 7 8 | ms.Position = 0; byte [] bytes = new byte [ms.Length]; ms.Read(bytes, 0, bytes.Length); foreach ( var item in bytes) { Console.Write(item.ToString( "X2" ) + " " ); } Console.WriteLine(String.Empty); |
再次执行结果如下:
这里我们发现用StreamWriter.Write输出多出了EF BB BF这3个字节
Google一下:多出来的这个玩意是 字节顺序记号(英语:byte-order mark,BOM)
在维基百科中可以查到:
编码 | 表示 (十六进制) | 表示 (十进制) |
---|---|---|
UTF-8 | EF BB BF |
239 187 191 |
UTF-16(大端序) | FE FF |
254 255 |
UTF-16(小端序) | FF FE |
255 254 |
UTF-32(大端序) | 00 00 FE FF |
0 0 254 255 |
UTF-32(小端序) | FF FE 00 00 |
255 254 0 0 |
UTF-7 | 2B 2F 76 和以下的一个字节:[ 38 | 39 | 2B | 2F ] |
43 47 118 和以下的一个字节:[ 56 | 57 | 43 | 47 ] |
en:UTF-1 | F7 64 4C |
247 100 76 |
en:UTF-EBCDIC | DD 73 66 73 |
221 115 102 115 |
en:Standard Compression Scheme for Unicode | 0E FE FF |
14 254 255 |
en:BOCU-1 | FB EE 28 及可能跟随着FF |
251 238 40 及可能跟随着255 |
ok,了解了这个东西后我们就就需要知道在StreamWriter.Write中能否用代码控制不输出这个BOM吗?
三、查找解决办法
开始反编译StreamWriter.Write这个方法:
大致猜测是红色方框的代码输出了BOM信息,ok再进去看:
果然在这里,看上图红框处,GetPreamble方法是获取编码的字节序列,和我们之前查到的信息完全一致。
好下面继续找这个haveWrittenPreamble有没设置的可能,在Init方法中找到了它的身影。
杯具了,CanSeed没有set方法,Write之前的Position肯定为0,至此结束。
四、结论
由上面的结论,我们可以确定:
1.如果双方协议无BOM时,可以使用Stream.Write方法来输出,或者使用StreamWriter.Write时加入new UTF8Encoding(false)参数。
2.有BOM时,我们可以通过GetPreamble和Stream.Write来完成StreamWriter.Write的功能。
参考文献:
谢谢FJ. Zhou提示
使用StreamWriter sw = new StreamWriter(ms, new UTF8Encoding(false));可以达到不输出BOM的需求。
谢谢dudu提示,已更正。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架