Stream.Write 与 StreamWriter.Write 的不同

一、测试方法是否结果相同
首先看下面两段代码1是StreamWriter.Write 2是Stream.Write:

1


代码如下:

Stream ms = new MemoryStream();
string str = "这是测试字符串";
StreamWriter sw = new StreamWriter(ms, Encoding.UTF8);
sw.Write(str);
sw.Flush();

2


代码如下:

Stream ms = new MemoryStream();
string str = "这是测试字符串";
byte[] buffer = Encoding.UTF8.GetBytes(str); 
ms.Write(buffer, 0, buffer.Length);
ms.Flush();

上面我们可以看到StreamWriter.Write的可读性更好一些。

但是这两段代码执行后的ms是否是相同的结果呢?

首先我们来看下长度吧,在代码最后分别加上

代码如下:

Console.WriteLine("StreamWriter.Write:{0}", ms.Length);
Console.WriteLine("Stream.Write:{0}", ms.Length);

执行后结果如下:

各位看官,看到这里有何想法?

二、深究原因
下面继续深究一下这个多出来的3个字节

在方法后面都加上如下一段代码将MemoryStream的内容以十六进制的形式打印出来

代码如下:

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的功能。

(0)

相关推荐

  • Stream.Write 与 StreamWriter.Write 的不同

    一.测试方法是否结果相同首先看下面两段代码1是StreamWriter.Write 2是Stream.Write: 1 复制代码 代码如下: Stream ms = new MemoryStream();string str = "这是测试字符串";StreamWriter sw = new StreamWriter(ms, Encoding.UTF8);sw.Write(str);sw.Flush(); 2 复制代码 代码如下: Stream ms = new MemoryStrea

  • PHP和.net中des加解密的实现方法

    php5.x版本,要添加php扩展php_mcrypt. PHP版: 复制代码 代码如下: class STD3Des {     private $key = "";     private $iv = ""; /**     * 构造,传递二个已经进行base64_encode的KEY与IV     *     * @param string $key     * @param string $iv     */     function __construct

  • C#不登录电脑启动程序

    阅读目录 创建系统服务 开启服务,启动程序 我们知道开机自启动程序如果在用户不登录的情况下是不启动的,但是服务类程序是可以跨过用户登录启动的,例如IIS服务,SQL服务.如果我们已经写好了桌面应用程序,又希望他开机自启动,那就需要借助系统服务在未登录的时候打开程序. 创建系统服务 在VS中创建Windows服务: 在Service的OnStart方法中,启动程序,代码如下: protected override void OnStart(string[] args) { if (!IsExist

  • C#将DataGridView中的数据保存到CSV和Excel中

    一.保存到CSV public static bool dataGridViewToCSV(DataGridView dataGridView) { if (dataGridView.Rows.Count == 0) { MessageBox.Show("没有数据可导出!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); return false; } SaveFileDialog saveFile

  • C#导入和导出CSV文件

    一.手工导出导出 1.winform void DataGridViewToExcel(DataGridView dataGridView1) { SaveFileDialog saveFileDialog = new SaveFileDialog(); saveFileDialog.Filter = "Execl files (*.xls)|*.xls"; saveFileDialog.FilterIndex = 0; saveFileDialog.RestoreDirectory

  • .Net笔记:System.IO之Stream的使用详解

    Stream在msdn的定义:提供字节序列的一般性视图(provides a generic view of a sequence of bytes).这个解释太抽象了,不容易理解:从stream的字面意思"河,水流"更容易理解些,stream是一个抽象类,它定义了类似"水流"的事物的一些统一行为,包括这个"水流"是否可以抽水出来(读取流内容):是否可以往这个"水流"中注水(向流中写入内容):以及这个"水流"

  • C#使用StreamReader和StreamWriter类读写操作文件

    StreamReader 类 (System.IO) | Microsoft 官方文档 StreamWriter 类 (System.IO) | Microsoft 官方文档 一.文本读写类: TextReader/TextWriter:文本读写,抽象类 1.TextReader文本读,其派生类: StreamReader:以一种特定的编码从字节流中读取字符. StringReader:从字符串读取. 2.TextWriter文本写,其派生类: StreamWriter:以一种特定的编码向流中写

  • Java8新特性Stream流实例详解

    什么是Stream流? Stream流是数据渠道,用于操作数据源(集合.数组等)所生成的元素序列. Stream的优点:声明性,可复合,可并行.这三个特性使得stream操作更简洁,更灵活,更高效. Stream的操作有两个特点:可以多个操作链接起来运行,内部迭代. Stream可分为并行流与串行流,Stream API 可以声明性地通过 parallel() 与sequential() 在并行流与顺序流之间进行切换.串行流就不必再细说了,并行流主要是为了为了适应目前多核机器的时代,提高系统CP

  • C# Stream 和 byte[] 之间的转换

    /* - - - - - - - - - - - - - - - - - - - - - - - -   * Stream 和 byte[] 之间的转换  * - - - - - - - - - - - - - - - - - - - - - - - */ /// <summary> /// 将 Stream 转成 byte[] /// </summary> public byte[] StreamToBytes(Stream stream) {     byte[] bytes 

  • TImage组件实现保存图片到Stream

    因为一个项目,不得不将图片保存到数据库中,需要的时候再从数据库中读取.初时,以为很简单,不就是一个Stream.事实上,也很简单.度娘一下,代码也很多,但,都是坑! 看一下TImage的源,Picture.Graphic下有一个loadfromStream和SavetoStream.如果没有猜错,那么直接用这两个函数就可以了.于是,我做了一个demo测试 demo里放了两个TImage.TImage1放一张图片,然后用代码将TImage1的图片保存到Stream.TImage2再从这个Strea

随机推荐