之前以為BinaryWriter寫string會嚴格按構造時指定的編碼(不指定則是無BOM的UTF8)寫入string的二進制,如下面的代碼:
//將字符串"a"寫入流,再拿到流的字節組data using (var ms = new MemoryStream()) { using (var bw = new BinaryWriter(ms)) { bw.Write("a"); } byte[] data = ms.ToArray(); }
因為字母a的utf8編碼是97,所以我預期data只有1個元素且值為97,而實際上,data有兩個元素,依次為1、97,顯然97代表a,但前面的1是什麼鬼,再試其它字符串,仍然會在前面多出1個甚至多個字節,值也比較漂浮,總之就是bw並沒有原原本本的寫入string的二進制,而是加了些料,這在嚴格要求字節正確的場景會出問題,如http請求體,服務器會對這些多出來的字節表示懵逼。遂搜索一番,發現MSDN、stackoverflow早有提到,前面多出來的字節實際上是表示string的長度,叫長度前綴(length-prefixed),據SO某答主的說法,這是供BinaryReader的ReadString方法用,知道長度,它才知道要讀取到哪裡。所以如果流的讀取方不是BinaryReader,這些長度前綴就是多余甚至是有害的,這種情況下就不能使用BinaryWriter.Write(string)方法,要寫入干淨的string二進制,可以這樣:
bw.Write(Encoding.UTF8.GetBytes("a"));//按需選用正確的編碼
即先用具體編碼得到string的字節組,再用BinaryWriter.Write(byte[])寫入該字節組。
-文畢-