C#中常用I/O流介紹、 FileStream類及FileMode、FileAccess、FileShare

yinghualeihenmei發表於2024-04-10

原文連結:https://zhuanlan.zhihu.com/p/558000060?utm_id=0

1、流的含義:

流可以視為一組連續的一維資料,包含開頭和結尾,並且其中的遊標指示了流的當前位置。抽象基類 Stream支援讀取和寫入位元組。

2、流涉及三個基本操作:

讀取 :將資料從流傳輸到資料結構(如位元組陣列)中。
寫入 : 將資料從資料來源傳輸到流。
查詢 :對流中的當前位置進行查詢和修改。

3、常見的流

C#中由許多型別的流(14種派生類),但是在處理檔案輸入/輸出時,最重要的型別為FileStream類,它提供了讀取或寫入檔案的方式。

C#中常見的流:

  • FileStream: 用於對檔案進行讀取和寫入操作。
  • IsolatedStorageFileStream:用於對獨立儲存中的檔案進行讀取或寫入操作。
  • MemoryStream:用於作為後備儲存對記憶體進行讀取和寫入操作,讀取速度比FileStream快。
  • BufferedStream :用於改進讀取和寫入操作的效能。
  • NetworkStream: 用於透過網路套接字進行讀取和寫入。
  • PipeStream: 用於透過匿名和命名管道進行讀取和寫入。
  • CryptoStream :用於將資料流連結到加密轉換。

4、先總結一下FileMode、FileAccess、FileShare

1.FileMode 指定作業系統開啟檔案的方式
FileMode 引數控制檔案是覆蓋、建立、開啟還是某種組合。 用於 Open 開啟現有檔案。 若要追加到檔案,請使用 Append。 若要截斷檔案或建立檔案(如果不存在),請使用 Create。

Append 若存在檔案,則開啟該檔案並查詢到檔案尾,或者建立一個新檔案。 FileMode.Append 只能與 FileAccess.Write 一起使用。

Create 指定作業系統應建立新檔案。 如果此檔案已存在,則會將其覆蓋。
CreateNew 指定作業系統應建立新檔案, 這需要 Write許可權。
Open 指定作業系統應開啟現有檔案。
OpenOrCreate 指定作業系統應開啟檔案(如果檔案存在);否則,應建立新檔案。
Truncate 指定作業系統應開啟現有檔案。 該檔案被開啟時,將被截斷為零位元組大小。
2.FileAccess 定義檔案的讀取、寫入或讀/寫訪問許可權的常量
Read 對檔案的讀訪問。 可從檔案中讀取資料。 與 Write 組合以進行讀寫訪問。
ReadWrite 對檔案的讀寫訪問許可權。 可從檔案讀取資料和將資料寫入檔案。
Write 檔案的寫訪問。 可將資料寫入檔案。 與 Read 組合以進行讀寫訪問。
3.FileShare包含用於控制其他 FileStream 物件對同一檔案可以具有的訪問型別的常數。
Delete 允許隨後刪除檔案。
Inheritable 使檔案控制代碼可由子程序繼承。 Win32 不直接支援此功能。
None 謝絕共享當前檔案。 檔案關閉前,開啟該檔案的任何請求(由此程序或另一程序發出的請求)都將失敗。
Read 允許隨後開啟檔案讀取。 如果未指定此標誌,則檔案關閉前,任何開啟該檔案以進行讀取的請求(由此程序或另一程序發出的請求)都將失敗。 但是,即使指定了此標誌,仍可能需要附加許可權才能夠訪問該檔案。
ReadWrite 允許隨後開啟檔案讀取或寫入。 如果未指定此標誌,則檔案關閉前,任何開啟該檔案以進行讀取或寫入的請求(由此程序或另一程序發出)都將失敗。 但是,即使指定了此標誌,仍可能需要附加許可權才能夠訪問該檔案。
Write 允許隨後開啟檔案寫入。 如果未指定此標誌,則檔案關閉前,任何開啟該檔案以進行寫入的請求(由此程序或另一進過程發出的請求)都將失敗。 但是,即使指定了此標誌,仍可能需要附加許可權才能夠訪問該檔案。
3 FileStream類
為檔案提供 Stream,既支援同步讀寫操作,也支援非同步讀寫操作。

3.1 常用構造方法、屬性和方法
構造方法、屬性和方法 描述
FileStream(String, FileMode, FileAccess, FileShare, Int32, FileOptions) 構造方法,使用指定的路徑、建立模式、讀/寫和共享許可權、其他 FileStreams 可以具有的對此檔案的訪問許可權、緩衝區大小和附加檔案選項初始化 FileStream類的新例項。
CanRead 如果流支援讀取,則為 true;如果流已關閉或是透過只寫訪問方式開啟的,則為 false
CanSeek 該值指示當前流是否支援查詢
CanTimeout 該值確定當前流是否可以超時
IsAsync FileStream 是非同步開啟還是同步開啟的。
Length 獲取流的長度(以位元組為單位)
Name 獲取 FileStream 中已開啟的檔案的絕對路徑。
Position 獲取或設定此流的當前位置。
BeginRead(Byte[], Int32, Int32, AsyncCallback, Object) 開始非同步讀操作。Byte[]:讀取存入陣列中,第一個Int32:陣列開始讀取的位置,第二個int32:陣列最大的長度。AsyncCallback:非同步處理後回撥的方法(回撥可理解為:B的方法在被A觸發的情況下去呼叫了A的方法。)
Close() 關閉當前流並釋放與之關聯的所有資源(如套接字和檔案控制代碼)。
CopyTo(Stream, Int32) 使用指定的緩衝區大小,從當前流中讀取位元組並將其寫入到另一流中。Stream:複製到的流,Int32:緩衝區的大小。
Dispose() 釋放由 Stream使用的所有資源。
Lock(Int64, Int64) 防止其他程序讀取或寫入。第一個Int64要鎖定的範圍的起始處、第二個Int64要鎖定的範圍。
Read(Byte[], Int32, Int32) 從流中讀取位元組塊並將該資料寫入給定緩衝區中。其中:第一個int32中的位元組偏移量,將在此處放置讀取的位元組,第二個int32最多讀取的位元組數。
Read(Span< Span >) 從當前檔案流中讀取位元組序列,並在該檔案流中按照讀取的位元組數提升位置。
ReadByte() 從檔案中讀取一個位元組,並將讀取位置提升一個位元組。
Seek(Int64, SeekOrigin) 將該流的當前位置設定為給定值。Int64:引數的位元組偏移量offset。SeekOrigin :型別的值,將開始位置、結束位置或當前位置指定為 offset 的參考點。有三個值:Begin(從流的起始位置開始跳躍) Current(繼續在當前的Position位置上進行跳躍) End(直接跳到結尾處)。如果 offset 為負,則需要在由指定的位元組數之前指定的新位置 origin offset 。 如果 offset 為零 (0) ,則新位置需要是指定的位置 origin 。 如果 offset 為正,則需要在由指定的位元組數後跟隨新位置 origin offset 。例如:aFile.Seek(-5,SeekOrigin.End); 從檔案的末尾向前查詢五個位元組。
ToString() 返回表示當前物件的字串。
WriteByte(Byte) 一個位元組寫入檔案流中的當前位置。
Write(Byte[], Int32, Int32) 將位元組塊寫入檔案流
Flush(Boolean) 清除此流的緩衝區,將所有緩衝資料都寫入到檔案中,並且也清除所有中間檔案緩衝區。
3.2 程式碼示例

public static void Main()
{
string path = @"G:\Desktop\archive1\MyTest.txt";
// 如果檔案存在則刪除檔案
if (File.Exists(path))
{
File.Delete(path);
}
//建立檔案
using (FileStream fs = File.Create(path))
{
AddText(fs, "This is some text");
AddText(fs, "This is some more text,");
AddText(fs, "\r\nand this is on a new line");
AddText(fs, "\r\n\r\nThe following is a subset of characters:\r\n");
for (int i = 1; i < 124; i++)
{
AddText(fs, Convert.ToChar(i).ToString());
}
}
//開啟流並讀取
using (FileStream fs = File.OpenRead(path))
{
//每一次讀取位元組的長度
byte[] b = new byte[2];
//將該流的當前位置設定為給定值,從流尾向前讀五個位元組
fs.Seek(-5, SeekOrigin.End);
//給定位元組編碼格式
UTF8Encoding temp = new UTF8Encoding(true);
while (fs.Read(b, 0, b.Length) > 0)
{
Console.Write(temp.GetString(b)+" ");
Console.WriteLine();
}
Console.WriteLine(fs.Name);
}
using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{ //
UTF8Encoding temp = new UTF8Encoding(true);
for (int i = 0; i < fs.Length; i++)
{
byte[] bytes = new byte[1];
bytes[0] = (byte)fs.ReadByte();
Console.Write(temp.GetString(bytes) +" ");
}
if (fs.CanRead)
{
Console.WriteLine("可讀");
}
else
{
Console.WriteLine("不可讀");
}
}
}
private static void AddText(FileStream fs, string value)
{
//給定編碼格式的位元組陣列
byte[] info = new UTF8Encoding(true).GetBytes(value);
//寫入位元組陣列
fs.Write(info, 0, info.Length);
}

 執行結果:

相關文章