zoukankan      html  css  js  c++  java
  • Stream.Write 与 StreamWriter.Write 的区别

    Stream.Write 与 StreamWriter.Write 是我们在向流中写数据时,最常用的方法。下面就详细讲解这两个方法。

    一、测试方法是否结果相同

    首先看下面两段代码左侧是StreamWriter.Write 右侧是Stream.Write:

    Stream ms = new MemoryStream();
    string str = "这是测试字符串";
    
    StreamWriter sw = new StreamWriter(ms, Encoding.UTF8);
    sw.Write(str);
    sw.Flush();
    
    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);

    执行后结果如下:

    image

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

    二、深究原因

    下面继续深究一下这个多出来的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);

    再次执行结果如下:

    image 

    这里我们发现用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这个方法:

    image

    大致猜测是红色方框的代码输出了BOM信息,ok再进去看:

    image

    果然在这里,看上图红框处,GetPreamble方法是获取编码的字节序列,和我们之前查到的信息完全一致。

    好下面继续找这个haveWrittenPreamble有没设置的可能,在Init方法中找到了它的身影。

    image

    杯具了,CanSeed没有set方法,Write之前的Position肯定为0,至此结束。

    四、结论

    由上面的结论,我们可以确定:

    1.如果双方协议无BOM时,可以使用Stream.Write方法来输出,或者使用StreamWriter.Write时加入new UTF8Encoding(false)参数

    2.有BOM时,我们可以通过GetPreamble和Stream.Write来完成StreamWriter.Write的功能。

    参考文献:

    维基百科  字节顺序记号

    MSND     Encoding.GetPreamble 方法

    谢谢FJ. Zhou提示

    使用StreamWriter sw = new StreamWriter(ms, new UTF8Encoding(false));可以达到不输出BOM的需求。

    谢谢dudu提示,已更正。

  • 相关阅读:
    只允许在input框输入文字,不能输入数字和其他字符
    阻止用户在input框输入数字
    centos 7.2安装和配置MongoDB
    Python基础
    Python小练习008
    Python小练习007
    Python小练习006
    Python错误集锦
    Python和MongoDB
    MongoDB笔记
  • 原文地址:https://www.cnblogs.com/sorex/p/2232056.html
Copyright © 2011-2022 走看看