【.NET Core】深入理解IO - FileSteam流
文章目錄
- 【.NET Core】深入理解IO - FileSteam流
- 一、IO流概述
- 二、文件流FileStream
- 2.1 FileStream概述
- 2.2 FileStream檢測流位置更改
- 2.3 FileStream構造函數
- 2.4 FileStream常用屬性
- 2.5 FileStream.Read方法
- 2.6 FileStream.Write方法
- 2.7 FileStream.Seek方法
- 2.8 FileStream.Flush 方法
- 三、FileStream總結

一、IO流概述
抽象類Stream
支持讀取和寫入字節。所有表示流的類都繼承自Stream
類。Stream
類及其派生類提供數據源和存儲庫的常見視圖。
流主要設計三個基本的操作:
- 讀取 - 將數據從流傳輸到數據結構中。
- 寫入 - 將數據從數據源傳輸到流。
- 查找 - 對流中的當前位置進行查詢和修改。
IO流常用的流包含一下幾個類,博主將在將來的博文中一一介紹。
FileStream
- 用于對文件進行讀取和寫入操作。IsolatedStorageFileStream
- 用于對獨立存儲中的文件進行讀取或寫入操作。MemoryStream
- 用于作為后備存儲對內存進行讀取和寫入操作。BufferedStream
- 用于改進讀取和寫入操作的性能。NetworkStream
- 用于通過網絡套接字進行讀取和寫入。PipStream
- 用于通過匿名和命名管道進行讀取和寫入。CryptoStream
- 用于將數據流鏈接到加密轉換。
二、文件流FileStream
2.1 FileStream概述
使用FileStream
類讀取、寫入、打開和關閉文件系統上的文件,以及操作其他與文件相關的操作句柄、包括管道、標注輸入和標注輸出。可以使用Write
和方法執行同步操作,或者ReadAsyncCopyToAsyncWriteAsync
以及FlushAsync
執行異步操作的方法。FlushReadCopyTo
使用異步方法執行資源密集型文件操作,而不阻止主線程。
FileStream
類實現IDisposable
接口。在使用完類型后,你應直接或間接釋放類型。如要直接釋放類型,請在try/catch
塊中調用其Dispose
方法。如要間接釋放類型,請使用using
語言構造。
2.2 FileStream檢測流位置更改
FileStream
當對象在其句柄上沒有獨占保留時,另一個線程可以同時訪問文件句柄,并更改與文件句柄關聯的操作系統文件指針的位置。在這種情況下,對象中的FileStream
緩存位置以及緩沖區中緩存的數據可能會受到損害。該FileStream
對象定期對訪問緩存緩沖區的方法執行檢查,以確保操作系統的句柄位置與對象使用的FileStream
緩存位置相同。
2.3 FileStream構造函數
FileStream(String,FileMode)
使用指定的路徑和創建模式初始化FileStream
類的新實例。
FileStream(String,FileStreamOptions)
使用指定的路徑、創建模式、讀/寫和共享權限、緩存區大小、其他文件選項、預分配大小及其FileStream
對同一文件的訪問權限初始化類的新實例FileSteam
。
FileStream(String,FileMode,FileAccess)
使用指定的路徑、創建模式和讀/寫權限初始化FileStream
類新實例。
FileStream(String,FileMode,FileAccess,FileShare,Int32,Boolean)
使用指定的路徑、創建模式、讀/寫和共享權限、緩沖區大小和同步或異步狀態初始化FileStream
類的新實例。
FileStream(String,FileMode,FileAccess,FileShare)
使用指定的路徑、創建模式、讀/寫權限和共享權限創建 FileStream
類的新實例
FileStream(String,FileModel,FileAccesss,FileShare,Int32,FileOptions)
使用指定的路徑、創建模式、讀/寫和共享權限、其他 FileStreams 可以具有的對此文件的訪問權限、緩沖區大小和附加文件選項初始化FileStream
類的新實例。
2.4 FileStream常用屬性
序號 | 屬性名 | 屬性說明 |
---|---|---|
1 | CanRead | 獲取一個值,該值指示當前流是否支持讀取 |
2 | CanSeek | 獲取一個值,該值指示當前流是否支持查詢 |
3 | CanTimeout | 獲取一個值,該值確定當前流是否可以超時 |
4 | CanWrite | 獲取一個值,該值指示當前流是否支持寫入 |
5 | IsAsync | 獲取一個值,它指示FileStream 是異步打開還是同步打開的 |
6 | Length | 獲取流的長度(以字節為單位) |
7 | Name | 獲取FileStream 中已打開的文件的絕對路徑 |
8 | Position | 獲取或設置此流的當前位置 |
9 | ReadTimeout | 獲取或設置一個值(以毫秒為單位),該值確定流在超時前將嘗試讀取的時間 |
10 | SafeFileHandle | 獲取 SafeFileHandle 對象,它代表當前FileStream 對象所封裝的文件的操作系統文件句柄。 |
11 | WriteTimeout | 獲取或設置一個值(以毫秒為單位),該值確定在超時前將嘗試寫入多長時間。 |
2.5 FileStream.Read方法
從流中讀取字節塊并將該數據寫入給定緩沖區中
- 重載
序號 | 方法 | 說明 |
---|---|---|
1 | Read(Byte[],Int32,Int32) | 從流中讀取字節塊并將該數據寫入給定緩沖區中 |
2 | Read(Span) | 從當前文件流中讀取字節序列,并在該文件流中按照讀取的字節數提升位置。 |
- 注解
方法Read
中offset參數(開始讀取的緩沖區索引)提供字節array
的偏移量,參數count
提供要從此流中讀取的最大字節數。返回的值是讀取的實際字節數。如果到達流的末尾,則返回的值為零。如果讀取操作成功,則流的當前位置將按讀取的字節數前進。如果發生異常,流的當前位置保持不變。
方法Read
僅在到達流的末尾后返回零,否則,Read
始終在返回之前至少從流中讀取一個字節。如果在調用Read
時流中沒有數據可用,則方法將阻塞,直到至少可以返回一個字節的數據。實現可以自由返回比請求的字節少,即使尚未到達流的末尾。
- 示例
public void FileReadDemo()
{string pathSource = @"c:\tests\source.txt";try{using (FileStream fsSource = new FileStream(pathSource,FileMode.Open,FileAccess.Read)){byte[] bytes = new byte[fsSource.Length];int numBytesToRead = (int)fsSource.Length;int numBytesRead = 0;while (numBytesToRead > 0){int n = fsSource.Read(bytes, numBytesRead, numBytesToRead);if (n == 0)break;numBytesRead += n;numBytesToRead -= n;}numBytesToRead = bytes.Length;using (FileStream fsNew = new FileStream(pathNew,FileMode.Create, FileAccess.Write)){fsNew.Write(bytes, 0, numBytesToRead);}}}catch(FileNotFoundException fileStreamException){Console.WriteLine(fileStreamException.Message) }
}
2.6 FileStream.Write方法
將字節的序列從只讀范圍寫入當前文件流,并按寫入的字節數向前移動此文件流中的當前位置。
- 重載
序號 | 方法 | 說明 |
---|---|---|
1 | Write(ReadOnlySpan) | 將字節的序列從只讀范圍寫入當前文件流,并按寫入的字節數向前移動此文件流中的當前位置 |
2 | Write(Byte[],Int32,Int32) | 將字節塊寫入文件流。 |
- 注解
CanWrite
使用,屬性確定當前實例是否支持寫入。WriteAsync
使用方法以異步方式寫入當前流。
如果吸入操作成功,則文件流中的位置將按寫入的字節數前進。如果發生異常,則文件流中的位置保持不變。
- 示例
if(fileStream.Length == 0)
{tempString =lastRecordText + recordNumber.ToString();fileStream.Write(uniEncoding.GetBytes(tempString),0,uniEncoding.GetByteCount(tempString));
}
2.7 FileStream.Seek方法
將該流的當前位置設置為給定值。
public override long Seek (long offset, System.IO.SeekOrigin origin);
offset
相對于origin
的點,從此處開始查找。SeekOrigin
使用SeekOrigin
類型的值,將開始位置,結束位置或當前位置指定為offset
的參考點。- 示例
public static void Main()
{long offset;int nextByte;using (FileStream fs = new FileStream(@"c:\temp\alphabet.txt", FileMode.Open, FileAccess.Read)){for (offset = 1; offset <= fs.Length; offset++){fs.Seek(-offset, SeekOrigin.End);Console.Write((char)fs.ReadByte());}Console.WriteLine();fs.Seek(20, SeekOrigin.Begin);while ((nextByte = fs.ReadByte()) > 0){Console.Write((char)nextByte);}Console.WriteLine();}
}
2.8 FileStream.Flush 方法
調用FileStream.Flush
方法時,會刷新操作系統I/O緩沖區。
I/O
緩沖區只有調用Flush
或釋放對象才會釋放緩沖區,否則不會刷新流的編碼器。如將StreamWriter.AutoFlush
為true
表示數據將從緩沖區刷新到流,但不會刷新編碼器狀態。這允許編碼器將其狀態保留,以便可以正確編碼一下字符塊。
三、FileStream總結
上面介紹了FileStream
的一般用法,如果需要有異常操作,異步讀取使用ReadAsync
方法,使用ReadAsync
方法 可以執行資源密集型文件操作,而不會阻止main
線程。 異步寫入使用WriteAsync
方法,WriteAsync
方法可以執行資源密集型文件操作,而不會阻止main
線程。在選擇FileStream
時,根據實際的使用場景選擇對應的方法完成對流的操作。