【转】C#中StreamWriter与BinaryWriter的区别兼谈编码。
參考:
1. 《C#高級(jí)編程》第六版
2.??文件流和數(shù)據(jù)流-C#程序設(shè)計(jì)教程
?
2010-7-11補(bǔ)充:
發(fā)現(xiàn)了一篇講編碼的深入而全面的好文章http://www.cnblogs.com/KevinYang/archive/2010/06/18/1760597.html
向文件寫入非字符類型數(shù)據(jù)
當(dāng)向文件中寫入非字符類型的數(shù)據(jù)時(shí),StreamWriter和BinaryWriter存在巨大差異。
StreamWriter是把各種類型的數(shù)據(jù)都轉(zhuǎn)化成字符,然后把字符按照一定的格式編碼出來的數(shù)據(jù)寫入文件中。
BinaryWriter是直接把數(shù)據(jù)在內(nèi)存中的真實(shí)狀態(tài)寫入到文件中。
例子:
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進(jìn)制碼.
??????? sw的輸出為31 30 30,占三個(gè)字節(jié)。代表了'1', '0', '0'的ASCII碼。它輸出的全是文本數(shù)據(jù)。
??????? bw的輸出為64 00 00 00 ,占四個(gè)字節(jié)。這正是100在內(nèi)存中的真實(shí)狀態(tài)。int類型占四個(gè)字節(jié)。
??????? 用記事本打開,sw的輸出顯示為:"100", bw的輸出顯示為 "d?? ", 因?yàn)?00對(duì)應(yīng)了ASCII碼的d。
?
BinaryWriter寫進(jìn)去的東西,StreamReader是認(rèn)不出來的,只能用BinaryReader的對(duì)應(yīng)方法來讀取,程序員記住自己是用什么方式寫的,然后在用BinaryReader讀取時(shí),指定好匹配的編碼方式,就可以將原來的數(shù)據(jù)還原了。???
??????? 你當(dāng)初寫進(jìn)去的是int型,就用BinaryReader.ReadInt32()來讀取。???
??????? 例如剛才寫進(jìn)去的100,可以這樣讀取:
??????? 這樣,a就等于100了
?
另外的例子:
BinaryWriter bw = new BinaryWriter(fs, Encoding.UTF32);bw.Write('a');輸出為:61 00 00 00,占4字節(jié),這就是字符'a'用UTF32格式編碼的結(jié)果。 讀取這個(gè)輸出 BinaryReader br = new BinaryReader(fs, Encoding.UTF32);Console.WriteLine(br.ReadChar()); BinaryWriter bw = new BinaryWriter(fs, Encoding.ASCII);bw.Write('a');輸出為:61,占1字節(jié),這就是字符'a'用ACSII格式編碼的結(jié)果。讀取這個(gè)輸出 BinaryReader br = new BinaryReader(fs, Encoding.ASCII);Console.WriteLine(br.ReadChar());?
?
文件的本質(zhì):
?
所謂的.txt文件,本質(zhì)不過是硬盤上一堆二進(jìn)制數(shù)據(jù)而已。
往文件中寫文本,就是把文本所對(duì)應(yīng)的編碼(也就是數(shù)字)寫進(jìn)txt文件。
?
當(dāng)你用記事本打開一個(gè)txt,就是使用“記事本”這個(gè)程序?qū)@堆二進(jìn)制數(shù)據(jù)進(jìn)行解釋。
比方說記事本在txt中讀到了一個(gè)64H,然后記事本去ASCII字庫里查詢64H代表什么字符,查到它代表‘d’,于是記事本就負(fù)責(zé)把‘d’這個(gè)字符給顯示出來。其實(shí)文件里存的不是‘d’,而是‘d’的ASCII編碼。
?
但問題是,世界上存在多種編碼方式,也就對(duì)應(yīng)了不同的字庫,比如GBK, 比如Big5, 比如Unicode,同樣的編碼在不同的字庫中對(duì)應(yīng)了不同的字。所以記事本對(duì)二進(jìn)制數(shù)據(jù)進(jìn)行解釋的時(shí)候,需要知道這些數(shù)據(jù)使用什么方式編碼,才能去對(duì)應(yīng)的字庫查它是哪個(gè)字。所以文件頭有時(shí)候會(huì)有一些標(biāo)識(shí)數(shù)據(jù),用來提示記事本這個(gè)txt是用什么方式編碼。
?
比如:文件頭的FF FE意味著本文用Unicode格式編碼。而FE FF意味著用BigEndianUnicode方式。所以FF FE 8B 73 被解釋為'王', FE FF 8B 73被解釋為‘譳’。
?
我們新建一個(gè)文本文檔,輸入'王',然后查看其16進(jìn)制的數(shù)據(jù),發(fā)現(xiàn)文檔數(shù)據(jù)為:CD F5。這是默認(rèn)編碼格式下的'王'的編碼。
然后將該文本文檔另存為Unicode格式的,發(fā)現(xiàn)其16進(jìn)制數(shù)據(jù)變成了:FF FE 8B 73。
再另存為Unicode big endin之后,16進(jìn)制數(shù)據(jù)變?yōu)?#xff1a;FE FF 73 8B。
這些底層數(shù)據(jù)的變化過程是由記事本程序來維護(hù)的,但無論底層數(shù)據(jù)怎么變動(dòng),我們看到的文本都是不變的。記事本程序并負(fù)責(zé)格式轉(zhuǎn)換并保證只改變編碼方式而不改變文本。
?
出現(xiàn)亂碼,就是對(duì)二進(jìn)制數(shù)據(jù)進(jìn)行了錯(cuò)誤的解釋。
?
向文件中寫入字符數(shù)據(jù)時(shí)
當(dāng)用于寫字符的時(shí)候,StreamWriter和BinaryWriter是差不多的。二者稍有區(qū)別。
看下面的例子:
? FileStream fs = File.Open("E:\\MyFile.txt", FileMode.OpenOrCreate, FileAccess.Write);StreamWriter sw = new StreamWriter(fs, Encoding.Unicode); sw.Write(‘王’); MyFile.txt內(nèi)容為:FF FE 8B 73StreamWriter sw = new StreamWriter(fs, Encoding.BigEndianUnicode); sw.Write(‘王’); MyFile.txt內(nèi)容為:FE FF 73 8B BinaryWriter bw = new BinaryWriter(fs, Encoding.Unicode); bw.Write(‘王’); MyFile.txt內(nèi)容為:8B 73BinaryWriter bw = new BinaryWriter(fs, Encoding.BigEndianUnicode); bw.Write(‘王’); MyFile.txt內(nèi)容為:73 8B?
??????????? 當(dāng)新建的時(shí)候,StreamWriter會(huì)順便寫入FF FE這樣的標(biāo)識(shí)數(shù)據(jù),而BinaryWriter不會(huì)寫入任何表示數(shù)據(jù),只把'王'的編碼寫入文件。
??????????? 當(dāng)append的時(shí)候,StreamReader設(shè)定的編碼方式是不會(huì)改變文檔原有的編碼方式的。
舉例來說。
?
?????? 有一個(gè)空的Unicode格式的MyFile.txt,該txt文件中只有兩個(gè)字節(jié)的數(shù)據(jù):FF FE。
?????? 執(zhí)行如下代碼:
?????? FileStream fs = File.Open("E:\\MyFile.txt", FileMode.Append, FileAccess.Write);
?????? StreamWriter sw = new StreamWriter(fs);
?????? sw.Write('王');
?????? 執(zhí)行之后,MyFile.txt內(nèi)的數(shù)據(jù)為:FF FE E7 8E 8B, 其中E7 8E 8B是StreamWriter采用默認(rèn)編碼格式對(duì)'王'進(jìn)行編碼的結(jié)果。
?????? 當(dāng)記事本程序試圖將FF FE E7 8E 8B解釋成文本時(shí),遇到FF FE會(huì)認(rèn)為這是Unicode編碼,于是把后邊的所有數(shù)據(jù)都按照Unicode的格式解釋,于是E7 8E 8B被解釋成了亂碼。把FF FE 改成00 00 之后,記事本找不到FF FE,于是就把這一坨數(shù)據(jù)按照默認(rèn)方式解釋,這就正確地將E7 8E 8B解釋成了‘王’字。
總結(jié)
以上是生活随笔為你收集整理的【转】C#中StreamWriter与BinaryWriter的区别兼谈编码。的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: AMD明年将成台积电5nm最大客户:锐龙
- 下一篇: 多家电商平台下架!上外男生给女生投放的牛