昨天討論了怎麼把記憶體對象序列化然後以二進位檔案的形式儲存和讀取。但是實際編程應用中,不是所有情況下都需要將整個對象寫到檔案裡,如果我們只想要寫部分資料(比如一個字串或者一個數字等)怎麼辦呢?這時就只需用到System.IO名稱空間裡的BinaryWriter和BinaryReader類。
研究過前輩寫的一些C++/C的二進位檔案讀取的代碼後,我發現C#在二進位檔案讀寫這方面處理得更加聰明一些。C/C++主要是通過記憶體位置精確控制讀取對應位,而在C#中實際上你不必考慮這些,只需要知道你存入資料的順序,讀取時按照存入順序依次讀取就可以了。比如說你用BinaryWriter對象的void
Write(int i)函數存入了一個int32位的資料,再用void Write(string str)存入了一個字串,再用void Write(double
d)存入了一個雙精確度浮點數,在讀取的時候,只需要依次用BinaryReader對象的int
ReadInt32()、string ReadString()、double
ReadDouble()依次讀取資料流就可以獲得int、sting、double三個類型的數值。至於資料流從哪一位開始讀到哪一位結束都不用你關心,都交給C#自己去判斷吧。當然,存取順序不一致會導致讀出意外的值或者什麼都讀不出來,或者超出資料流範圍。
另外如果你堅持像C++/C那樣自己控制讀寫位置的話,也可以通過Stream的long
Seek(int Offset,SeekOrigin
origin)函數來設定。
以下範例程式碼(只給出了關鍵代碼):
string path = Application.StartupPath + "\\data.db";//二進位檔案路徑 private void button1_Click(object sender, EventArgs e)//存為檔案 { Person per = new Person() { name = "文文lele", age = 12, height = 1.50 };//執行個體化一個資料 Stream st = new FileStream(path, FileMode.Create); BinaryWriter bw = new BinaryWriter(st); bw.Write(per.age);//先int bw.Write(per.name);//再string bw.Write(per.height);//最後double bw.Close(); st.Close(); } private void button2_Click(object sender, EventArgs e)//讀取檔案 { Stream st = new FileStream(path, FileMode.Open); BinaryReader br = new BinaryReader(st); Person pr = new Person();//一個未被具體指明的 pr.age = br.ReadInt32();//先int pr.name = br.ReadString();//再string pr.height = br.ReadDouble();//最後double textBox1.Text = pr.ToString();//最後文字框會顯示:名字:文文lele\r\n年齡:12\r\n身高1.50 br.Close(); st.Close(); } } class Person { public string name { set; get; } public int age { set; get; } public double height { set; get; } public override string ToString() { return "名字:" + name.ToString() + "\r\n年齡:" + age.ToString() + "\r\n身高:" + height.ToString(); } }
如果想要使用Stream的long Seek(int Offset,SeekOrigin origin)函數來設定從哪開始讀,則讀取的代碼應該改為如下:
private void button2_Click(object sender, EventArgs e))//讀取檔案 { Stream st = new FileStream(path, FileMode.Open); BinaryReader br = new BinaryReader(st); Person pr = new Person();//一個未具體化的例子 st.Seek(4, SeekOrigin.Begin);//因為二進位檔案中儲存的第一個是32位的年齡(整型預設32位),佔4位元組,所以名字從第4位元組開始(8位為1位元組,32位即4位元組) pr.name = br.ReadString(); st.Seek(0, SeekOrigin.Begin);//年齡記錄在開始處 pr.age = br.ReadInt32(); st.Seek(-8, SeekOrigin.End);//身高是64位的雙精確度浮點型,佔8位元組,放在最後,所以從後往前數8個位元組 pr.height = br.ReadDouble(); textBox1.Text = pr.ToString();//最後文字框會顯示:名字:文文lele\r\n年齡:12\r\n身高1.50和第一種方法沒有變 br.Close(); st.Close(); }
兩種讀法或得相同的效果,這裡為了使string類型長度固定可以放在最後,也可以使用StringBuilder建立指定長度字串。