StreamWaiter類和StreamReader類的用法
事實上, StreamReader為了性能的考慮, 在自己的內部內置並維護了一個byte buffer。 如果在聲明StreamReader對象的時候沒有指定這個buffer的尺寸, 那么它的默認大小是1k。 如果是文件流, 那么這個buffer的默認大小是4K。 所有Read操作,都直接或間接轉換為了對這個buffer的操作。StreamReader不能seek,只能通過baseStream.seek和StreamReader.DiscardBufferData()一起來實現StreamReader的定向輸出的功能。內部的basestream=外部傳入的filestream等
默認情況下,StreamWriter 不是線程安全的。有關線程安全包裝的信息,請參見 TextWriter.Synchronized。
StreamReader類的用法
StreamReader 工作原理
構造函數
- StreamReader(Stream)
- StreamReader(String)
- StreamReader(Stream, Boolean)
- StreamReader(Stream, Encoding)
- StreamReader(String, Boolean)
- StreamReader(String, Encoding)
- StreamReader(Stream, Encoding, Boolean)
- StreamReader(String, Encoding, Boolean)
- StreamReader(Stream, Encoding, Boolean, Int32)
- StreamReader(String, Encoding, Boolean, Int32)
- StreamReader(Stream, Encoding, Boolean, Int32, Boolean)
- Boolean :是否又字節順序標記 即 BOM全稱是Byte Order Mark 可以通過Encoding的方法GetPreamble()來判斷這編碼有沒有BOM,目前CLR中只有下面5個Encoding有BOM。
可以通過Encoding的方法GetPreamble()來判斷這編碼有沒有BOM,目前CLR中只有下面5個Encoding有BOM。
UTF-8: EF BB BF
UTF-16 big endian: FE FF
UTF-16 little endian: FF FE
UTF-32 big endian: 00 00 FE FF
UTF-32 little endian: FF FE 00 00
用Encoding的靜態屬性Unicode,UTF8,UTF32構造的Encoding都是默認帶有BOM的,如果你想在寫一個文本時(比如XML文件,如果有BOM,會有亂碼的),不想帶BOM,那么就必須用它們的實例,
Encoding encodingUTF16=new UnicodeEncoding(false, false);//第二個參數必須要為false Encoding encodingUTF8=new UTF8Encoding(false); Encoding encodingUTF32=new UTF32Encoding(false,false);//第二個參數必須要為false
讀寫文本和BOM的關系可以參考園子里這篇博客,講的很詳細我就不重復了,.NET(C#):字符編碼(Encoding)和字節順序標記(BOM)
具體的功能
//構造函數 //using (StreamReader sr = new StreamReader(pat,Encoding.Unicode))//更具文件內容選擇合適的編碼格式讀取文件。不指定就采用UTF8編碼 using (StreamReader sr = new StreamReader(pat)) { //屬性 Stream stream = sr.BaseStream; //返回基流,stream 是字節碼。 Console.WriteLine(stream.GetType()); //輸出 System.IO.FileStream Console.WriteLine(sr.CurrentEncoding); //當前流讀取器使用的編碼,默認是本機編碼(當構造器不指定時),如果構造方法指定了,輸出的就是構造方法指定的編碼 //方法 //Read()應用 char[] burffer1 = new char[9];// {'a', 's', 'd', 'f', 'g', 'h', 'j', 'k' }; char[] burffer2 = new char[9]; var s = sr.Read();//讀取當前指針的所指向的字符 ,讀取完成后指針向前移一個字符。 Console.WriteLine(Convert.ToChar(s)); //A //Read(Span<Char>) Span<char> span = new Span<char>(burffer1);//將數組轉成指針數組 sr.Read(span);//將流中存入 span,存滿后就停止。charPos又向前移動了9個位置 Console.WriteLine(string.Join("",span.ToArray()));//SCII hell //Read(Char[], Int32, Int32) sr.Read(burffer2, 2, 4);//從sr 重charPos 指針當前所指向的位子開始讀取 4個字符,存入burffer數組的3-7位置。charPos++向前移動了4個位置 Console.WriteLine(String.Join("", burffer2));//鏈接字符數組並且打印 o I Console.WriteLine(sr.BaseStream.Position);//讀取BaseStream指針的絕對位置 //這兩種方式都是判斷BaseStream 中數據是否都讀取完畢 Console.WriteLine(sr.BaseStream.Position==sr.BaseStream.Length); //true 判斷基礎流的內存是否都讀取完成了,BaseStream指針的絕對位置和長度相同時候,就說明讀取完成了。
調用 DiscardBufferedData 方法 重置內部緩沖區 會降低性能,只應在絕對必要的情況下調用。 Console.WriteLine(sr.EndOfStream);// true 判斷基礎流的內存是否都讀取完成了。 sr.BaseStream.Seek(0, SeekOrigin.Begin); //0表示相對於SeekOrigin.Begin的位置。SeekOrigin.Begin表示在哪里讀取流 sr.DiscardBufferedData(); // 清空sr內部緩沖區,因為BaseStream內容都已經讀取完成。所以清空內部緩沖區后,sr不會再次從BaseStream讀取數據到內部緩沖區中。 if (sr.Peek() == -1) { Console.WriteLine("內部緩沖區內容已經讀取完成。"); } sr.BaseStream.Seek(0, SeekOrigin.Begin);//重置BaseStream 指針,觸發sr內部緩沖區又會開始讀取 BaseStream的內容。 if (sr.Peek() > -1) { Console.WriteLine("又可以讀取了"); } //判斷是否讀取完成。讀取完成返回值是-1,Peek()也read()也都是返回accii的編碼 while (sr.Peek() > -1) { //ReadLine() 的應用 var ren = sr.ReadLine();//ASCII hello I am programmer hello 因為緩存和指針都重置過了。從頭開始讀取 Console.WriteLine(sr.Peek()); Console.WriteLine(ren); } //第二次重置,一次性讀取本文內容。 sr.DiscardBufferedData(); sr.BaseStream.Seek(0, SeekOrigin.Begin); //0表示相對於SeekOrigin.Begin的位置。SeekOrigin.Begin表示在哪里讀取流 Console.WriteLine(sr.ReadToEnd());//從 charPos++ 所指向的字符開始讀取 一直讀取到內容結束。因為指針已經知道末尾,所以返回為空 }
SeekOrigin枚舉
Begin | 0 | 指定流的開始位置。 |
Current | 1 | 指定流中的當前位置。 |
End | 2 | 指定流的結束位置。 |
StreamWriter類的用法
在講這個用法之前,必須了解一個概念:
Stream類型不支持終結,所有必須顯示調用Dispose()方法將緩存中的數據flush到FileStream。不顯示調用就會造成數據丟失。
VS支持托管調試助手MDA來找出特點種類的常見編程錯誤。激活一個MDA就像拋出一個異常.使用方法如下:
調試>窗口>異常設置>搜索datalost 並且勾選,streamWriter 會在對象的數據丟失時候停止。
.NET中的Encoding類和BOM
在.NET的世界里,我們經常用Encoding的靜態屬性來得到一個Encoding類,從這里得到的編碼默認都是提供BOM的(如果支持BOM的話)。
如果你想讓指定編碼不提供BOM,那么需要手動構造這個編碼類。
//不提供BOM的Encoding編碼 Encoding utf8NoBom = new UTF8Encoding(false); Encoding utf16NoBom = new UnicodeEncoding(false, false); Encoding utf32NoBom = new UTF32Encoding(false, false);
另外這里都是構造Little-endian的,Big-endian構造函數里也有參數。
其次UnicodeEncoding類代表UTF16編碼。
文本寫入時,StreamWriter類
和File.WriteAllText類
方法的默認編碼都是不帶BOM的UTF8。
和StreamReader一樣 , StreamWriter
也有內部緩沖區,在Write(Char)先將內如寫入內部緩沖區,如果設置了sw.AutoFlush = true;屬性那么每執行一次Write(Char),就會刷新一次內部緩沖區,將
緩沖區的內容寫入BaseStream,然后更新更新到相應的文件。或者執行sw.Close()、swDispose()關閉內部緩沖區和baseStream也會刷新緩沖區。或者在 using(StreamWriter sw = new StreamWriter(fs)){。。。}結束后刷新緩沖區。
StreamWriter會關閉內部流的對象fs,因此不用關閉stream/filestream。
構造函數
StreamWriter(Stream) 使用 UTF-8 編碼及默認的緩沖區大小,為指定的流初始化 StreamWriter 類的新實例。
StreamWriter(String) 用默認編碼和緩沖區大小,為指定的文件初始化 StreamWriter 類的一個新實例。
StreamWriter(Stream, Encoding) 使用指定的編碼及默認的緩沖區大小,為指定的流初始化 StreamWriter 類的新實例。
StreamWriter(String, Boolean) 用默認編碼和緩沖區大小,為指定的文件初始化 StreamWriter 類的一個新實例。 string path,Boolean append 如果該文件存在,則可以將其覆蓋或向其追加。 如果該文件不存在,此構造函數將創建一個新文件。
StreamWriter(Stream, Encoding, Int32) 使用指定的編碼及緩沖區大小,為指定的流初始化 StreamWriter 類的新實例。int32 緩沖區大小
StreamWriter(String, Boolean, Encoding) 使用指定的編碼和默認的緩沖區大小,為指定的文件初始化 StreamWriter 類的新實例。 如果該文件存在,則可以將其覆蓋或向其追加。 如果該文件不存在,此構造函數將創建一個新文件。
StreamWriter(Stream, Encoding, Int32, Boolean) 使用指定的編碼和緩沖區大小,為指定的流初始化 StreamWriter 類的新實例,並可以選擇保持流處於打開狀態。
StreamWriter(String, Boolean, Encoding, Int32) 使用指定編碼和緩沖區大小,為指定路徑上的指定文件初始化 StreamWriter 類的新實例。 如果該文件存在,則可以將其覆蓋或向其追加。 如果該文件不存在,此構造函數將創建一個新文件。
具體功能
class StreamWaiterTest { static void Main() { //設置桌面為當前目錄 Directory.SetCurrentDirectory(Environment.GetFolderPath(Environment.SpecialFolder.Desktop)); DirectoryInfo directory = Directory.CreateDirectory("StreamWaiter"); directory.Create(); if (directory.Exists) { DirectoryInfo subDir = directory.CreateSubdirectory("sub"); subDir.Create(); FileInfo fileinfo = new FileInfo(Path.Combine(subDir.FullName, "text.txt")); FileStream fs = fileinfo.Create(); if (fileinfo.Exists) { using(StreamWriter sw = new StreamWriter(fs)) { char[] cha = { '1', '2', '3', '4', '6' }; //屬性 Console.WriteLine(sw.Encoding.GetPreamble()); sw.AutoFlush = true;//該值指示 StreamWriter 在每次調用 Write(Char) 之后是否都將其緩沖區刷新到基礎流。 只有刷新到BaseStream 才能寫到"text.txt"中 // 方法 sw.WriteLine("first line"); sw.WriteLine("second line "); sw.WriteLine("third line "); sw.Write(cha);//將字符數組寫入BaseStream sw.BaseStream.Seek(0, SeekOrigin.Begin);//重置BaseStream.的指針,將指針指向最開始位置。 sw.WriteLine("four line "); sw.Flush();//清理當前寫入器的所有緩沖區,並使所有緩沖數據寫入基礎流。 } } using (StreamWriter sws = new StreamWriter(Path.Combine(subDir.FullName, "text.txt"), true))//以追加方式新建流 { sws.Write("fsfsdfsfsdfsdf"); } } } }