1. 程式人生 > >Stream.Write 與 StreamWriter.Write 的不同

Stream.Write 與 StreamWriter.Write 的不同



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