【转】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解释成了‘王’字。
【转】C#中StreamWriter与BinaryWriter的区别兼谈编码。相关推荐
- C#中StreamWriter与BinaryWriter的区别兼谈编码。
原文:http://www.cnblogs.com/ybwang/archive/2010/06/12/1757409.html 参考: 1. <C#高级编程>第六版 2. 文件流和数据 ...
- 大牛市中大师们如何选股长袖善舞——兼谈本周经济与股市
大牛市中大师们如何选股长袖善舞--兼谈本周经济与股市 11 结果,又是涨停.新股国信证券在打开涨停前成交量巨大:结果后续者又一个涨停.你想会有涨停,真的就会有涨停.--这就是牛市.此外,在事业单 ...
- python中的编码和解码_Python中“is”和“==”之间的区别,以及编码和解码,与
Python中'is'和'=='的区别,以及编码与解码 Python中'=='和'is'的区别 (1)Python中'==' Python中'==比较变量的值,如果值相同返回True,如果不同返回Fl ...
- php中empty与isset的区别,再谈php中empty与isset区别详解
empty与isset在php中一个是为空,另一个判断是是否为一个存在的变量了,下面小编来给各位同学介绍php中empty与isset区别,欢迎各位同学进入参考. empty是判断变量值是非空或非零的 ...
- python中break和continue的区别
python中break和continue的区别 break 结束for 或者while 循环 后面还没循环到的 不再循环 continue 当满足某种条件时结束当前值的循环 后面没有循环的继续循环 ...
- java中separator_java - File.separator和路径中的斜杠之间的区别
java - File.separator和路径中的斜杠之间的区别 在Java Path-String中使用/和普通的File.separator有什么区别? 与双反斜杠相比,/平台独立似乎不是原因, ...
- PHP中self和static的区别,php中self与static的区别
原文链接,猛击这里. php中self与static的区别 通过一些示例,我们可以很容易看出self和static的区别.假定我们有class Car – 它有两个方法,model和getModel. ...
- php 抽象类 接口 区别,PHP中抽象类、接口的区别与选择分析
本文实例分析了PHP中抽象类.接口的区别与选择.分享给大家供大家参考,具体如下: 区别: 1.对接口的使用是通过关键字implements.对抽象类的使用是通过关键字extends.当然接口也可以通过 ...
- php $this self,php中self与$this的区别
学习php中self与$this的区别. 先来看下parent与self的例子: /* * parent与self的区别 * by www.jbxue.com */ class A{ function ...
最新文章
- BZOJ 1412 [ZJOI2009]狼和羊的故事(最小割)
- Python-OpenCV学习 -- 台式机外接USB摄像头的视频读取
- maven仓库用法与settings.xml配置汇总
- hdu 5783——Divide the Sequence
- python-操作数据库的练习
- 【操作系统】实验四 主存空间的分配和回收
- ds6708 symbol 驱动_symbol DS6708设置及使用手册中文版.pdf
- 刘意-Java基础视频(基础部分)笔记(一)
- 计算机应用基础信息素养,计算机应用基础:信息素养+Office 2013办公自动化
- python语言实现图像的手绘效果
- 划重点 2022面试必刷461道大厂架构面试真题汇总+面经+简历模板
- 年近30,半失业状态:定制化,正在拖垮年轻人
- 键盘输入一个高精度的正整数N,去掉其中任意S个数字后剩下的数字按原左右次序将组成一个新的正整数。编程对给定的N和S,寻找一种方案使得剩下的数字组成的新数最小。(C++)(贪心法)
- matlab中plot矢量长度,关于plot函数矢量长度弹错的问题
- win10实现开机播放视频
- nyoj 1364-治安管理 (INT_MAX)
- TCP/IP实现(九) 插口I/O
- 2023年完美解决:windows 11/win 11使用经典右键菜单(win10版右键菜单)
- 尔宾团队角色(Belbin Team Roles),亦被称为贝尔宾团队角色表(Belbin Team Inventory)...
- typora如何导出深色背景的pdf
热门文章
- Scrapy安装报错
- python练习题-day25
- C++11并发之std::thread
- 微信小程序image组件中aspectFill和widthfix模式应用详解
- 1.Python数据类型、方法
- [iOS] 建立与使用Framework
- GitHub---最简单的使用
- sql server数据库还原方法
- 通汇手机为何卖得那么红火
- mongodb如何根据字段(数组类型)的长度排序_大数据存储技术选型(七)——MongoDB设计模式及索引优化...