【转】C#中StreamWriter与BinaryWriter的区别兼谈编码。

参考:

1. 《C#高级编程》第六版

2.  文件流和数据流-C#程序设计教程

 

2010-7-11补充:

  发现了一篇讲编码的深入而全面的好文章http://www.cnblogs.com/KevinYang/archive/2010/06/18/1760597.html

向文件写入非字符类型数据

当向文件中写入非字符类型的数据时,StreamWriter和BinaryWriter存在巨大差异。


StreamWriter是把各种类型的数据都转化成字符,然后把字符按照一定的格式编码出来的数据写入文件中。


BinaryWriter是直接把数据在内存中的真实状态写入到文件中。

例子:

class Program
{static void Main(string[] args){                FileStream fs = File.Open("E:\\MyFile.txt", FileMode.OpenOrCreate, FileAccess.Write);StreamWriter sw = new StreamWriter(fs);BinaryWriter bw = new BinaryWriter(fs);sw.Write(100);bw.Write(100);                          }
}


        用UEdit查看MyFile.txt的16进制码.
        sw的输出为31 30 30,占三个字节。代表了'1', '0', '0'的ASCII码。它输出的全是文本数据。
        bw的输出为64 00 00 00 ,占四个字节。这正是100在内存中的真实状态。int类型占四个字节。


        用记事本打开,sw的输出显示为:"100", bw的输出显示为 "d   ", 因为100对应了ASCII码的d。

 

BinaryWriter写进去的东西,StreamReader是认不出来的,只能用BinaryReader的对应方法来读取,程序员记住自己是用什么方式写的,然后在用BinaryReader读取时,指定好匹配的编码方式,就可以将原来的数据还原了。   
        你当初写进去的是int型,就用BinaryReader.ReadInt32()来读取。   
        例如刚才写进去的100,可以这样读取:

        class Program{static void Main(string[] args){                FileStream fs = File.Open("E:\\MyFile.txt", FileMode.Open, FileAccess.Read);BinaryReader br = new BinaryReader(fs);int a = br.ReadInt32();                           }}


        这样,a就等于100了

 

另外的例子:

            BinaryWriter bw = new BinaryWriter(fs, Encoding.UTF32);bw.Write('a');输出为:61 00 00 00,占4字节,这就是字符'a'用UTF32格式编码的结果。
            读取这个输出
              BinaryReader br = new BinaryReader(fs, Encoding.UTF32);Console.WriteLine(br.ReadChar());
 
 
            BinaryWriter bw = new BinaryWriter(fs, Encoding.ASCII);bw.Write('a');输出为:61,占1字节,这就是字符'a'用ACSII格式编码的结果。读取这个输出
              BinaryReader br = new BinaryReader(fs, Encoding.ASCII);Console.WriteLine(br.ReadChar());

 

 

文件的本质:

 

所谓的.txt文件,本质不过是硬盘上一堆二进制数据而已。

往文件中写文本,就是把文本所对应的编码(也就是数字)写进txt文件。

 

当你用记事本打开一个txt,就是使用“记事本”这个程序对这堆二进制数据进行解释。
比方说记事本在txt中读到了一个64H,然后记事本去ASCII字库里查询64H代表什么字符,查到它代表‘d’,于是记事本就负责把‘d’这个字符给显示出来。其实文件里存的不是‘d’,而是‘d’的ASCII编码。

 

但问题是,世界上存在多种编码方式,也就对应了不同的字库,比如GBK, 比如Big5, 比如Unicode,同样的编码在不同的字库中对应了不同的字。所以记事本对二进制数据进行解释的时候,需要知道这些数据使用什么方式编码,才能去对应的字库查它是哪个字。所以文件头有时候会有一些标识数据,用来提示记事本这个txt是用什么方式编码。

 

比如:文件头的FF FE意味着本文用Unicode格式编码。而FE FF意味着用BigEndianUnicode方式。所以FF FE 8B 73 被解释为'王', FE FF 8B 73被解释为‘譳’。

 

我们新建一个文本文档,输入'王',然后查看其16进制的数据,发现文档数据为:CD F5。这是默认编码格式下的'王'的编码。
然后将该文本文档另存为Unicode格式的,发现其16进制数据变成了:FF FE 8B 73。
再另存为Unicode big endin之后,16进制数据变为:FE FF 73 8B。
这些底层数据的变化过程是由记事本程序来维护的,但无论底层数据怎么变动,我们看到的文本都是不变的。记事本程序并负责格式转换并保证只改变编码方式而不改变文本。

 

出现乱码,就是对二进制数据进行了错误的解释。

 

向文件中写入字符数据时


当用于写字符的时候,StreamWriter和BinaryWriter是差不多的。二者稍有区别。

看下面的例子:

 
FileStream fs = File.Open("E:\\MyFile.txt", FileMode.OpenOrCreate, FileAccess.Write);StreamWriter sw = new StreamWriter(fs, Encoding.Unicode);
sw.Write(‘王’);
MyFile.txt内容为:FF FE 8B 73StreamWriter sw = new StreamWriter(fs, Encoding.BigEndianUnicode);
sw.Write(‘王’);
MyFile.txt内容为:FE FF 73 8B BinaryWriter bw = new BinaryWriter(fs, Encoding.Unicode);
bw.Write(‘王’);
MyFile.txt内容为:8B 73BinaryWriter bw = new BinaryWriter(fs, Encoding.BigEndianUnicode);
bw.Write(‘王’);
MyFile.txt内容为:73 8B

 


            当新建的时候,StreamWriter会顺便写入FF FE这样的标识数据,而BinaryWriter不会写入任何表示数据,只把'王'的编码写入文件。
            当append的时候,StreamReader设定的编码方式是不会改变文档原有的编码方式的。

举例来说。

 
       有一个空的Unicode格式的MyFile.txt,该txt文件中只有两个字节的数据:FF FE。

       执行如下代码:


       FileStream fs = File.Open("E:\\MyFile.txt", FileMode.Append, FileAccess.Write);
       StreamWriter sw = new StreamWriter(fs);
       sw.Write('王');


       执行之后,MyFile.txt内的数据为:FF FE E7 8E 8B, 其中E7 8E 8B是StreamWriter采用默认编码格式对'王'进行编码的结果。
       当记事本程序试图将FF FE E7 8E 8B解释成文本时,遇到FF FE会认为这是Unicode编码,于是把后边的所有数据都按照Unicode的格式解释,于是E7 8E 8B被解释成了乱码。把FF FE 改成00 00 之后,记事本找不到FF FE,于是就把这一坨数据按照默认方式解释,这就正确地将E7 8E 8B解释成了‘王’字。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/437501.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

WebStrom里设置angular提示,可以在html中提示ts文件的内容

下面这样就是可以提示到 在settings->languages&frameworks->javaScript->Libraries 下把你的工程添加进去 这是我添加进来的,Type类型为project 我改了中文

【转】关于字符编码,你所需要知道的

字符编码的问题看似很小,经常被技术人员忽视,但是很容易导致一些莫名其妙的问题。这里总结了一下字符编码的一些普及性的知识,希望对大家有所帮助。 还是得从ASCII码说起 说到字符编码,不得不说ASCII码的简史。计算机一开始发明…

SuperSet连接Hive失败(客户端报日志拒绝连接)

先上报错,百度无数SuperSet的解决办法整了三四天无果后,打了两天游戏突然想到了个找问题的办法 INFO:thrift.transport.TSocket:Could not connect to (192.168.228.131, 10000) Traceback (most recent call last):File "/opt/module/miniconda3/…

【转】谈谈Unicode编码,简要解释UCS、UTF、BMP、BOM等名词

这是一篇程序员写给程序员的趣味读物。所谓趣味是指可以比较轻松地了解一些原来不清楚的概念,增进知识,类似于打RPG游戏的升级。整理这篇文章的动机是两个问题: 问题一: 使用Windows记事本的“另存为”,可以在GBK、U…

angular8实现对象数组根据某个属性排序(多个也可以)

代码中col是传进来的对象的属性名 toLowerCase()将字符串转换为小写。 arrayInfos是数组,存储的是对象 这里我是配上一个上下切换的箭头使用的,点击切换上下方向并且排序 sort方法排序操作的是原始数组 如果在属性相等的情况下,想根据另…

【转】刨根究底字符编码之一——关键术语解释(上)

声明:本系列文章参考了网上的大量资料,除了少部分资料由于未作大量修改(但基本也有少量修改,因为网上文章随意性较大,如若不改反而让人迷糊)而标明了出处之外,其余由于已作了大量改写,因此没有再一一说明&a…

angular8多选框实现点击整行任意位置<tr>就可以选中多选框

代码&#xff1a; <tr *ngFor"let d of EnergyUseInfos" (click)"selectEnergyUses(d)"><td style"text-align: left"><input type"checkbox" style"margin: auto" name"{{d}}" [(ngModel)]"…

【转】刨根究底字符编码之零——前言

前言 一、 字符编码是计算机世界里最基础、最重要的一个主题之一。不过&#xff0c;在计算机教材中却往往浮光掠影般地草草带过&#xff0c;甚至连一本专门进行深入介绍的著作都找不到&#xff08;对这一点我一直很困惑&#xff0c;为什么就没有哪位大牛对这个如此基础、重要…

JAVA使用ByteArrayOutputStream、ByteArrayInputStream将对象序列化反序列化,通过JAVA socket实现对象在网络中传输

1.序列化和反序列化&#xff1a; 序列化是对象(类的实例)转换成字节数组或者字符串通过网络传输或者存储到本地文件。反序列化&#xff1a;就是将字节数组或字符串在转换成对象实例的过程。&#xff08;因为在网络中传输或者写本地文件&#xff0c;是不能使用对象的&#xff0…

【转】刨根究底字符编码之二——关键术语解释(下)

关键术语解释(下) 如前所述&#xff0c;现代字符编码模型共分为5层&#xff0c;下面分层进行简要介绍。 一、第1层 抽象字符表ACR (Abstract Character Repertoire抽象字符清单)&#xff1a;明确字符的范围(即确定支持哪些字符) 1. 抽象字符表ACR是一个编码系统支持的所有抽…

正则表达式来判断Sql语句中Select到from之间使用了*而不是字段名

正则&#xff1a;这里大小写转换用的java的toLowerCase()方法&#xff0c;或者自己改一改正则也可以。 \bselect\b((?!\bfrom\b).)*?\*.*?\bfrom\b主要就是用来判断select到from之间是不是用了*而不是使用字段名来进行查询&#xff0c;以此来规范Sql语句&#xff01; publ…

【转】刨根究底字符编码之三——字符编码的由来

字符编码的由来 一、为什么需要对字符进行编码 1. 计算机一开始发明出来时是用来解决数字计算问题的&#xff0c;后来人们发现&#xff0c;计算机还可以做更多的事&#xff0c;例如文本处理。 但计算机其实挺“笨”的&#xff0c;它只“认识”010110111000…这样由0和1两个数…

SpringMVC配置没问题却却找不到页面,页面显示404

在Artifacts下此工程下新建一个lib文件夹&#xff0c;存放jar包&#xff0c;因为idea新建modules的时候不是直接创建的web项目&#xff1a; 选中lib点加号把jar导入进去&#xff0c;然后重启tomcat

【转】刨根究底字符编码之四——EASCII及ISO 8859字符编码方案

1. 计算机出现之后&#xff0c;首先逐渐从美国发展到了欧洲。由于欧洲很多国家所用到的字符中&#xff0c;除了基本的、美国也用的那128个ASCII字符之外&#xff0c;还有很多衍生的拉丁字母等字符。比如&#xff0c;在法语中&#xff0c;字母上方有注音符号&#xff1b;而欧洲…

tomcat乱码问题解决

tomcat安装目录下conf文件夹下的logging.properties文件&#xff0c;将java.util.logging.ConsoleHandler.encoding编码为GBK&#xff0c;如图&#xff1a;

【转】HMAC哈希消息认证码及算法原理

HMAC算法原理 HMAC算法是一种基于密钥的报文完整性的验证方法 &#xff0c;其安全性是建立在Hash加密算法基础上的。它要求通信双方共享密钥、约定算法、对报文进行Hash运算&#xff0c;形成固定长度的认证码。通信双方通过认证码的校验来确定报文的合法性。 HMAC算法可以用来…

RestFul风格学习

传统的url是这样的 RestFul是这样的

【转】c#快捷键

CTRL SHIFT B生成解决方案 CTRL F7 生成编译 CTRL O 打开文件 CTRL SHIFT O打开项目 CTRL SHIFT C显示类视图窗口 F4 显示属性窗口 SHIFT F4显示项目属性窗口 CTRL SHIFT E显示资源视图 F12 转到定义 CTRL F12转到声明 CTRL ALT J对象浏览 CTRL ALT …

Angular使用Console.log()打印出来的数据没问题,点击详情后数据变了

我在一个界面添加数据使用updataEvent将对象返回给另一个界面后&#xff0c;在onUpData中处理时使用 this.xxxxx d&#xff0c;直接将地址值给了变量&#xff0c;当这个方法结束后d被重置了&#xff0c;所以this.xxx的值也消失了,这里要使用下面的方法复制一个对象出来。 this…

【转】刨根究底CSS(1):开篇

01 一道小菜 CSS很难&#xff0c;这应该是绝大多数Web开发人员的共识。 什么&#xff1f;你并不觉得很难&#xff1f;那我就先上一道小菜&#xff0c;请君品尝。 这是个乍一看&#xff0c;让人觉得很诡异的案例…… 算了&#xff0c;本来想滔滔不绝介绍一番&#xff0c;但一…