C#流總結

1. 什麼是流

數據流(Stream)是對串行傳輸數據的一種抽象表示,是對輸入/輸出的一種抽象。數據有來源和目的地,銜接兩者的就是串流對象。用比喻的方式來說或,數據就好比水,串流對象就好比水管,通過水管的銜接,水由一端流向另一端,如下圖所示:

從應用程序的角度來說,如果將數據從來源取出,可以試用輸入(讀)串流,把數據儲存在內存緩衝區;如果將數據寫入目的地,可以使用輸出(寫)串流,把內存緩衝區的數據寫入目的地:

當希望通過網絡傳輸數據,或者對文件數據進行操作時,首先需要將數據轉化爲數據流。典型的數據流和某個外部數據源相關,數據源可以是文件、外部設備、內存、網絡套接字等。根據數據源的不同,.Net提供了多個從Stream類派生的子類,每個類代表一種具體的數據流類型,如何磁盤文件直接相關的文件流類FileStream,和套接字相關的網絡流類NetworkStream,和內存相關的內存流類MemoryStream等。

2. 流的基本操作

  • 寫入:將數據從內存緩衝區傳輸到外部源;
  • 讀取:將數據從外部源傳輸到內存緩衝區;
  • 查找:重新設置流的當前位置,以便隨機讀寫。但並不是所有的流類型都支持查找,如網絡流類沒有當前位置的概念,就不支持查找。

Stream是虛擬類,它以及它的派生類都提供了Read和Write方法,可以支持在字節級別上對數據進行讀寫。Read方法從當前字節流讀取字節放至內存緩衝區,Write方法把內存緩衝區的字節寫入當前流中。流的寫入和讀取操作都是基於字節的。

3. 流的種類

(1)文件流 FileStream

FileStream流繼承與Stream類,一個FileStream類的實例實際上代表一個文件流,使用FileStream類可以對文件系統上是文件進行讀取、寫入、打開和關閉操作。

創建FileStream實例

1、.Net提供多種獲取FileStream對象的方法,其中構造函數就有10多種,我們看下典型的構造函數順便講解下參數含義:

  1. public FileStream(string path, FileMode mode, FileAccess access);
參數說明:
path指明文件所在的路徑信息;
mode是FileMode的枚舉值,表示文件打開或創建的方式,含義如下:
  • CreateNew:指定操作系統應創建新文件,如果文件已經存在,則引發IOException;
  • Create:指定操作系統應創建新文件,如果文件已經存在,它將被覆蓋;
  • Open:指定操作系統應打開現有文件,如果文件不存在,則引發FileNotFoundException;
  • OpenOrCreate:指定操作系統應打開文件,如果文件不存在,則創建新文件;
  • Truncate:指定操作系統應打開現有文件,文件一旦打開,就將截斷爲零字節大小;
  • Append:打開先有文件並把Position設置至文件尾,如果文件不存在將創建新文件。Append只能同FileAccess.Write一起使用;

access是FileAccess的枚舉值,它控制對文件的訪問權限,含義如下:

  • Read:打開文件用於只讀;
  • Write:打開文件用於只寫;
  • ReadWrite:打開文件,用於讀寫;

2、除了FileStream類本身提供的構造函數外,System.IO命名空間下的File和FileInfo類也提供了創建FileStream對象的方法。其中OpenRead方法返回只讀文件流,OpenWrite方法返回只寫文件流。如:

  1. FileStream fs=File.OpenRead(@"c:\file.txt");
FileStream的讀寫方法:
  1. public override int Read(
  2. byte[] array, //內存緩衝區,儲存從文件流中讀取的數據
  3. int offset, //array開始寫入數據的下標值
  4. int count //從文件流中讀取的字節大小
  5. );
  6.  
  7. public override void Write(
  8. byte[] array, //內存緩衝區,存儲了要寫入流的字節數據
  9. int offset, // 從array的下標值開始取數據
  10. int count //要寫入的字節數
  11. );
FileStream實例 
  1. try
  2. {
  3. //寫入
  4. FileStream fileStream = new FileStream(@"d:\test.txt", FileMode.OpenOrCreate);
  5. byte[] content = Encoding.UTF8.GetBytes("我愛我家");
  6. fileStream.Write(content, 0, content.Length);
  7. fileStream.Position = 0; //設置當前位置
  8. content = Encoding.UTF8.GetBytes("我愛你家");
  9.  
  10. fileStream.Write(content, 0, content.Length);
  11. fileStream.Close();
  12.  
  13. //讀取
  14. fileStream = new FileStream(@"d:\test.txt", FileMode.Open);
  15. content = new byte[fileStream.Length];
  16. fileStream.Read(content, 0, content.Length);
  17. Console.WriteLine(Encoding.UTF8.GetString(content));
  18. }
  19. catch (Exception ex)
  20. {
  21. Console.WriteLine(ex.Message);
  22. }

(2)內存流 MemoryStream

和文件流佈同,MemoryStream類表示的是保存在內存中的數據流,由內存流封裝的數據可以在內存中直接訪問。內存一般用於暫時緩存數據以降低應用程序對臨時緩衝區和臨時文件的需要。

既然字節數據也在內存中存儲,爲什麼還要引入內存流的概念呢?這是因爲內存流和字節數組雖然都位於程序緩衝區,但是具有不同特性。內存流相對於字節數組而言,具有流特有的特性,並且容量可自動增長,在數據加密以及對長度不定的數據進行緩存等場合,使用內存流比較方便。

創建MemoryStream實例

MemoryStream有多種構造函數,部分舉例如下:

  • public MemoryStream();該構造函數初始分配的容量大小爲0,隨着數據的不斷寫入,其容量可以不斷地自動擴展。
  • public MemoryStream(byte[] buffer);根據字節數組buffer初始化,實例的容量大小規定爲字節數組的長度。
  • public MemoryStream(int capacity);容量固定爲capacity。

MemoryStream實例

  1. MemoryStream mem = new MemoryStream();
  2. Console.WriteLine("初始分配的容量:"+mem.Capacity+" 初始使用量:"+mem.Length);
  3. byte[] content = Encoding.UTF8.GetBytes("我愛我家");
  4. mem.Write(content, 0, content.Length);
  5. Console.WriteLine("初始分配的容量:" + mem.Capacity + " 初始使用量:" + mem.Length);

(3)網絡流NetWorkStream

網絡流的意思是數據在網絡的各個位置之間是以連續的字節形式傳輸的,NetWorkStream只能用於面向連接的套接字。

對於NetWorkStream流,寫入操作是指從來源端內存緩衝區到網絡上的數據傳輸;讀取操作是從網絡上到接收端內存緩衝區的數據傳輸。

4. 流的輔助操作流的寫入和讀取操作都是基於字節的,很多時候不太方便,所以針對.NET提供了Stream的操作類,可以直接操作字符,而不用進行編碼轉換。

(1)StreamWriter和StreamReader

StreamWriter類主要完成一種特定的編碼從流中讀取字符的功能,它的構造函數和常用方法如下:

  • StreamWriter(Stream stream),構造函數,StreamWriter不僅能對FileStream對象,而且能夠對NetWorkStream、MemoryStream等繼承了Stream類的流對象進行封裝;
  • StreamWriter(string path),構造函數,如需要處理的是文件流,則可直接利用文件路徑創建以UTF8編碼的StreamWriter對象;
  • Write(string value),方法,向數據流寫入數據;
  • WriteLine(string value),方法,向數據流寫入數據,並追加一個換行符(Unix)或回車換行符(Windows);
  • Close(),方法,關閉流,釋放資源;

StreamReader類主要以特定的編碼向流中寫入字符,它的構造函數和常用方法如下:

  • StreamReader(Stream stream),構造函數,利用流對象創建StreamReader對象;
  • StreamReader(string path),構造函數,如需要處理的是文件流,則可直接利用文件路徑創建以UTF8編碼的StreamReader對象;
  • string ReadLine(),方法,讀取數據直到遇到換行符(Unix)或回車換行符(Windows);
  • string ReadToEnd(),方法,讀取到文件尾的全部數據
  • int Peek(),方法,返回數據中下一個可用字符的編碼值,如到達文件末尾則返回-1;
  • Close(),方法,關閉流,釋放資源;

StreamWriter和StreamReader實例

  1. try
  2. {
  3. //寫入
  4. StreamWriter sw = new StreamWriter(@"d:\abc.txt");
  5. sw.WriteLine("我愛我家");
  6. sw.Close();
  7.  
  8. //讀取
  9. StreamReader sr = new StreamReader(@"d:\abc.txt");
  10. Console.WriteLine(sr.ReadToEnd());
  11. }
  12. catch (Exception ex)
  13. {
  14. Console.WriteLine(ex.Message);
  15. }

(2)BinaryReader和BinaryWriter

爲了操作圖像、壓縮文件等二進制流文件,System.IO還提供了BinaryReader類和BinaryWriter類,用於二進制模式的讀寫流。
BinaryReader的每個讀方法都有一個對應的寫方法,比如針對不同的數據結構,BinaryReader類提供了ReadByte、ReadBoolean、ReadInt、ReadInt16、ReadString等,與之對應的BinaryReader類則提供了多個重載的Write方法,分別對應上面的讀方法,所以使用起來非常方便。例如,當Write方法傳遞的參數是Int32類型時,利用BinaryWriter的Write方法可用將Int32類型數據轉化爲長度爲4的字節數組,並將字節流傳遞給一個Stream對象。

BinaryReader和BinaryWriter實例

  1. byte[] sendData;
  2. using (MemoryStream mem = new MemoryStream()) {
  3. BinaryWriter writer = new BinaryWriter(mem, Encoding.UTF8);
  4. writer.Write(SocketTools.strConvertToHexByte(SocketTools.md5(packageHead.CarIdentifier, 32)));
  5. writer.Write(packageHead.ProjectIdentifier);
  6. writer.Write(packageHead.ModelIdentifier);
  7. writer.Write(packageHead.ProtocolVersion);
  8. writer.Write(SocketTools.reverseShort(packageHead.RequestSerial));
  9. writer.Write(SocketTools.reverseInt32(packageHead.PacketTimestamp));
  10. writer.Write(SocketTools.reverseShort(packageHead.FunctionNo));
  11. writer.Write(SocketTools.reverseShort(packageHead.DataLength));
  12. writer.Write(msg.ToCharArray());
  13. sendData = mem.ToArray();
  14. writer.Close();
  15. }
流輔助操作類本身不是流,它只是一種讓流數據更容易操作的輔助工具。沒有這些輔助類,流一樣可以正常工作,只是稍微麻煩一些。流使用後必須及時關閉,可以手動刷新內容,也可以在關閉時自動刷新。一定要明確哪些是流,哪些是流操作類。

流輔助類在操作流之前,需要指定流的編碼格式,只有指定正確的編碼格式,才能從流中讀取正確的數據。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章