BinaryWriter和BinaryReader和MemoryStream類讀寫內存

C#的FileStream類提供了最原始的字節級上的文件讀寫功能,但我們習慣於對字符串操作,於是StreamWriter和 StreamReader類增強了FileStream,它讓我們在字符串級別上操作文件,但有的時候我們還是需要在字節級上操作文件,卻又不是一個字節 一個字節的操作,通常是2個、4個或8個字節這樣操作,這便有了BinaryWriter和BinaryReader類,它們可以將一個字符或數字按指定 個數字節寫入,也可以一次讀取指定個數字節轉爲字符或數字。

1.BinaryWriter類

BinaryWriter類以二進制形式將基元類型寫入流,並支持用特定的編碼寫入字符串。


常用的方法:

Close      關閉當前的BinaryWriter和基礎流

Seek       設置當前流中的位置

Write      將值寫入當前流


2.BinartReader類

BinartReader類用特定的編碼將基元數據類型讀作二進制值。


常用的方法:

Close         關閉當前閱讀器及基礎流

Read          從基礎流中讀取字符,並提升流的當前位置

ReadBytes     從當前流將count個字節讀入字節數組,並使當前位置提升count個字節

ReadInt32     從當前流中讀取4個字節有符號整數,並使流的當前位置提升4個字節

ReadString    從當前流讀取一個字符串。字符串有長度前綴,一次7位地被編碼爲整數



下面看一個實例:

BinaryWriter 和 BinaryReader 類用於讀取和寫入數據,而不是字符串。

  1. using UnityEngine;
  2. using System;
  3. using System.Text;
  4. using System.IO;
  5. using System.Collections;
  6. using System.Collections.Generic;
  7. public class FileOperator : MonoBehaviour {
  8. // Use this for initialization
  9. void Start () {
  10. WriteFile ();
  11. ReadFile();
  12. }
  13. void ReadFile() // 讀取文件
  14. {
  15. FileStream fs = new FileStream ("D:\\MemoryStreamTest.txt", FileMode.Open, FileAccess.Read);
  16. BinaryReader r = new BinaryReader (fs);
  17. //以二進制方式讀取文件中的內容
  18. int i = r.ReadInt32 ();
  19. float f = r.ReadSingle ();
  20. double d = r.ReadDouble ();
  21. bool b = r.ReadBoolean ();
  22. string s = r.ReadString();
  23. Debug.Log (i);
  24. Debug.Log (f);
  25. Debug.Log (d);
  26. Debug.Log (b);
  27. Debug.Log (s);
  28. r.Close ();
  29. fs.Close ();
  30. }
  31. void WriteFile() // 寫入文件
  32. {
  33. FileStream fs = new FileStream ("D:\\BinaryStreamTest.txt", FileMode.OpenOrCreate);
  34. BinaryWriter w = new BinaryWriter (fs);
  35. //以二進制方式向創建的文件中寫入內容
  36. w.Write (666); // 整型
  37. w.Write (66.6f); // 浮點型
  38. w.Write (6.66); // double型
  39. w.Write(true); // 布爾型
  40. w.Write ("六六六"); // 字符串型
  41. w.Close ();
  42. fs.Close();
  43. }
  44. }

MemoryStream和BufferedStream都派生自基類Stream,因此它們有很多共同的屬性和方法,但是每一個類都有自己獨特的用法。這兩個類都是實現對內存進行數據讀寫的功能,而不是對持久性存儲器進行讀寫。

讀寫內存-MemoryStream類

MemoryStream類用於向內存而不是磁盤讀寫數據。MemoryStream封裝以無符號字節數組形式存儲的數據,該數組在創建MemoryStream對象時被初始化,或者該數組可創建爲空數組。可在內存中直接訪問這些封裝的數據。內存流可降低應用程序中對臨時緩衝區和臨時文件的需要。

下表列出了MemoryStream類的重要方法:

1、Read():讀取MemoryStream流對象,將值寫入緩存區。

2、ReadByte():從MemoryStream流中讀取一個字節。

3、Write():將值從緩存區寫入MemoryStream流對象。

4、WriteByte():從緩存區寫入MemoytStream流對象一個字節。

Read方法使用的語法如下:

mmstream.Read(byte[] buffer,offset,count) 

其中mmstream爲MemoryStream類的一個流對象,3個參數中,buffer包含指定的字節數組,該數組中,從offset到(offset +count-1)之間的值由當前流中讀取的字符替換。Offset是指Buffer中的字節偏移量,從此處開始讀取。Count是指最多讀取的字節數。Write()方法和Read()方法具有相同的參數類型。

MemoryStream類的使用實例:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.IO;
  6. namespace ConsoleApplication1
  7. {
  8. class Program
  9. {
  10. static void Main()
  11. {
  12. int count;
  13. byte[] byteArray;
  14. char[] charArray;
  15. UnicodeEncoding uniEncoding = new UnicodeEncoding();
  16. // Create the data to write to the stream.
  17. byte[] firstString = uniEncoding.GetBytes("一二三四五");
  18. byte[] secondString = uniEncoding.GetBytes("上山打老虎");
  19. using (MemoryStream memStream = new MemoryStream(100))
  20. {
  21. // Write the first string to the stream.
  22. memStream.Write(firstString, 0, firstString.Length);
  23. // Write the second string to the stream, byte by byte.
  24. count = 0;
  25. while (count < secondString.Length)
  26. {
  27. memStream.WriteByte(secondString[count++]);
  28. }
  29. // Write the stream properties to the console.
  30. Console.WriteLine("Capacity={0},Length={1},Position={2}\n", memStream.Capacity.ToString(), memStream.Length.ToString(), memStream.Position.ToString());
  31. // Set the position to the beginning of the stream.
  32. memStream.Seek(0, SeekOrigin.Begin);
  33. // Read the first 20 bytes from the stream.
  34. byteArray = new byte[memStream.Length];
  35. count = memStream.Read(byteArray, 0, 20);
  36. // Read the remaining bytes, byte by byte.
  37. while (count < memStream.Length)
  38. {
  39. byteArray[count++] = Convert.ToByte(memStream.ReadByte());
  40. }
  41. // Decode the byte array into a char array
  42. // and write it to the console.
  43. charArray = new char[uniEncoding.GetCharCount(byteArray, 0, count)];
  44. uniEncoding.GetDecoder().GetChars(byteArray, 0, count, charArray, 0);
  45. Console.WriteLine(charArray); Console.ReadKey();
  46. }
  47. }
  48. }
  49. }

在這個實例代碼中使用了using關鍵字。注意:

using 關鍵字有兩個主要用途:

1、作爲指令,用於爲命名空間創建別名或導入其他命名空間中定義的類型。

例如:

  1. using System; 

2、作爲語句,用於定義一個範圍,在此範圍的末尾將釋放對象。

  1. using(Connection conn=new Connection(connStr))  
  2. {  
  3. }  
  4. //使用using關鍵字可及時銷燬對象 

MemoryStream.Capacity 屬性 取得或設定配置給這個資料流的位元組數目。

MemoryStream.Position 屬性 指定當前流的位置。

MemoryStream.Length 屬性獲取用字節表示的流長度。

SeekOrigin()是一個枚舉類,作用設定流的一個參數。

SeekOrigin.Begin我得理解就是文件的最開始,“0”是偏移,表示跳過0個字節。寫2就是跳過2個字節。

MemoryStream類通過字節讀寫數據。本例中定義了寫入的字節數組,爲了更好的說明Write和WriteByte的異同,在代碼中聲明瞭兩個byte數組,其中一個數組寫入時調用Write方法,通過指定該方法的三個參數實現如何寫入。

另一個數組調用了WriteByte方法,每次寫入一個字節,所以採用while循環來完成全部字節的寫入。寫入MemoryStream後,可以檢索該流的容量,實際長度,當前流的位置,將這些值輸出到控制檯。通過觀察結果,可以確定寫入MemoryStream流是否成功。

調用Read和ReadByte兩種方法讀取MemoryStream流中的數據,並將其進行Unicode編碼後輸出到控制檯。







讀取內存流中的數據


在.NET中,使用抽象基類System.IO.Stream代表流,它提供Read和Write兩個方法。由於數據流的有序性,因此流對象還有一個讀寫指針,爲此,Stream類還有一個Seek方法用於移動讀寫指針。  


字符串與字節數組間的互相轉化:

  1. string str = "內存大小";
  2. byte[] temp = Encoding.UTF8.GetBytes (str); // 字符串轉化爲字節數組
  3. string s = Encoding.UTF8.GetString (temp); // 字節數組轉化爲字符串
  4. Debug.Log (s);

Encoding用法比較簡單,如果只是字節和字符的互相轉換,GetBytes()和GetChars()這兩個方法及它們的重載基本上會滿足你所有要求。

GetByteCount()及其重載是得到一個字符串轉換成字節時實際的字節個數。

GetCharCount()及其重載是得到一個字節數組轉換成字符串的大小。

Decoder.GetChars 方法

在派生類中重寫時,將指定字節數組的字節序列和內部緩衝區中的任何字節解碼到指定的字符數組。
在派生類中重寫時,將一個字節序列解碼爲一組字符。

Java裏一個byte取值範圍是-128~127, 而C#裏一個byte是0~255.

首位不同. 但是底層I/O存儲的數據是一樣的

FileStream對象的數據來自文件,而MemoryStream對象的數據來自內存緩衝區。這兩個類都繼承自Stream類。 

MemoryStream的數據來自內存中的一塊連續區域,這塊區域稱爲“緩衝區(Buffer)”。可以把緩衝區看成一個數組,每個數組元素可以存放一個字節的數據。

  1. 在創建MemoryStream對象時,可以指定緩衝區的大小,並且可以在需要的時候更改。
  2. //字節數組
  3. byte[] buffer = new byte[600];
  4. //填充字節數組
  5. private void CreateExampleData()
  6. {
  7. for(int i=0; i<600; i++)
  8. {
  9. //byte類型的數最大不能超過255,用256取模實現
  10. buffer[i] = (byte)(i%256);
  11. }
  12. }
  13. 內存流的基本使用方法:
  14. private void OnTestMemory()
  15. {
  16. //創建測試數據
  17. CreateExampleData();
  18. //創建內存流對象,初始分配50字節的緩衝區
  19. MemoryStream mem = new MemoryStream(50);
  20. //向內存流中寫入字節數組的所有數據
  21. mem.Write(buffer,0,buffer.GetLength(0));
  22. MessageBox.Show("寫入數據後的內存流長度:" + mem.Length.ToString());
  23. MessageBox.Show("分配給內存流的緩衝區大小:" + mem.Capacity.ToString());
  24. mem.SetLength(550);
  25. MessageBox.Show("調用SetLength方法後的內存流長度:" + mem.Length.ToString());
  26. mem.Capacity = 620;//此值不能小於Length屬性
  27. MessageBox.Show("調用Capacity方法後緩衝區大小:" + mem.Capacity.ToString());
  28. //將讀寫指針移到距流開頭10個字節的位置
  29. mem.Seek(10,SeekOrigin.Begin);
  30. MessageBox.Show(mem.ReadByte().ToString());
  31. mem.Close();
  32. }
  33. 內存流的Length屬性代表了其中存放的數據的真實長度,而Capacity屬性則代表了分配給內存流的內存空間大小。
  34. 可以使用字節數組創建一個固定大小的MemoryStream,
  35. MemoryStream mem = new MemoryStream(buffer);
  36. 這時,無法再設置Capacity屬性的大小。
  37. 還可以創建只讀的內存流對象。
  38. MemoryStream mem = new MemoryStream(buffer,false);
  39. FlieStream用於存取文件。
  40. 創建文件並寫入內容:
  41. //創建一個新文件
  42. FileStream fsForWrite = new FileStream("test.data",FileMode.Create);
  43. try
  44. {
  45. //寫入一個字節
  46. fsForWrite.WriteByte(100);
  47. CreateExampleData();
  48. //將字節數組寫入文件
  49. fsForWrite.Write(buffer,0,buffer.GetLength(0));
  50. }
  51. catch(Exception ex)
  52. {
  53. MessageBox.Show(ex.Message);
  54. }
  55. finally
  56. {
  57. //關閉文件
  58. fsForWrite.Close();
  59. }
  60. 打開文件並讀取內容:
  61. private void ReadFromFile()
  62. {
  63. FileStream fsForRead = new FileStream("test.data",FileMode.Open);
  64. try
  65. {
  66. //讀入一個字節
  67. MessageBox.Show("文件的第一個字節爲:"+fsForRead.ReadByte().ToString());
  68. //讀寫指針移到距開頭10個字節處
  69. fsForRead.Seek(10,SeekOrigin.Begin);
  70. byte[] bs = new byte[10];
  71. //從文件中讀取10個字節放到數組bs中
  72. fsForRead.Read(bs,0,10);
  73. }
  74. catch(Exception ex)
  75. {
  76. MessageBox.Show(ex.Message);
  77. }
  78. finally
  79. {
  80. fsForRead.Close(); }
  81. }
  82. 如果一個程序退出了,但它打開的文件沒有被關閉,將導致其他程序無法修改或刪除此文件。

FileStream與MemoryStream間的相互作用:

-----解決方案--------------------
  FileStream fs = new FileStream(path, FileMode.Open); 
  byte[] data = new byte[fs.Length]; 
  fs.Read(data, 0, data.Length); 
  fs.Close();
  MemoryStream ms = new MemoryStream(data);

------解決方案--------------------

 ///定義並實例化一個內存流,以存放圖片的字節數組。
MemoryStream m = new MemoryStream();
///獲得當前路徑
string strAppPath = AppDomain.CurrentDomain.BaseDirectory; //獲得可執行文件的路徑。
///獲得圖片路徑 
string strPath = strAppPath + "img\\default.jpg"; 
///圖片讀入FileStream 
FileStream f = new FileStream(strPath, FileMode.open); 
///把FileStream寫入MemoryStream 
m.SetLength(f.Length); 
f.Read(m.GetBuffer(), 0, (int)f.Length); 
m.Flush(); 
f.Close();

------解決方案--------------------
            FileStream fs = new FileStream(fileName, FileMode.Open);
            byte[] MyData = new byte[fs.Length];
            fs.Read(MyData, 0, (int)fs.Length);
            fs.Close();
            MemoryStream ms = new MemoryStream(MyData);

------解決方案--------------------
MemoryStream ms = new MemoryStream(File.ReadAllBytes("c:\\1.jpg"));
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章