FileStream 是 .NET 直接操作作業系統檔案控制代碼的核心類別,提供位元組級別的隨機存取能力。雖然 StreamReader/Writer 處理文字更方便,但以下場景必須使用 FileStream:
| 枚舉值 | 檔案存在 | 檔案不存在 | 典型用途 |
|---|---|---|---|
CreateNew | 拋出例外 | 建立新檔 | 獨佔建立,防止覆寫 |
Create | 覆寫(截斷) | 建立新檔 | 最常用,確保乾淨狀態 |
Open | 開啟現有 | 拋出例外 | 唯讀或讀寫現有檔 |
OpenOrCreate | 開啟現有 | 建立新檔 | 設定檔、快取檔 |
Truncate | 清空內容 | 拋出例外 | 保留建立時間,重置內容 |
Append | 指標移至末尾 | 建立新檔 | 日誌記錄、追加寫入 |
Read:唯讀,允許多人同時開啟Write:唯寫,通常搭配 AppendReadWrite:讀寫皆可,預設值
// 允許其他程序同時讀取,但禁止寫入
var fs = new FileStream("data.bin", FileMode.Open, FileAccess.Read, FileShare.Read);
FileStream 維護內部指標,Read/Write 會自動推進。Seek(offset, origin) 讓你精確定位:
var fs = new FileStream("data.bin", FileMode.OpenOrCreate, FileAccess.ReadWrite);
// 從開頭偏移 100 位元組
fs.Seek(100, SeekOrigin.Begin);
// 從目前位置向前 20 位元組
fs.Seek(20, SeekOrigin.Current);
// 從檔案結尾倒數 50 位元組(負數)
fs.Seek(-50, SeekOrigin.End);
// 取得目前指標位置
long pos = fs.Position;
// 取得檔案總長度
long len = fs.Length;
public static string ReadBlock(string path, long offset, int count)
{
byte[] buffer = new byte[count];
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read))
{
fs.Seek(offset, SeekOrigin.Begin);
int read = fs.Read(buffer, 0, count);
// 實務中需檢查 read == count,否則為讀到檔案結尾
}
// 位元組轉字串(指定編碼)
return Encoding.UTF8.GetString(buffer, 0, count);
}
public static void WriteText(string path, string text, Encoding encoding = null)
{
encoding ??= Encoding.UTF8;
byte[] bytes = encoding.GetBytes(text); // 字串 -> 位元組陣列
using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write))
{
fs.Write(bytes, 0, bytes.Length);
// fs.Flush(); // using 區塊結束自動 Flush + Close
}
}
public async Task ReadAsync(string path, long offset, int count)
{
byte[] buffer = new byte[count];
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read,
bufferSize: 4096, useAsync: true))
{
await fs.SeekAsync(offset, SeekOrigin.Begin);
await fs.ReadExactlyAsync(buffer); // .NET 6+ 確保讀滿
}
return buffer;
}
關鍵參數: bufferSize(預設 4KB)影響系統呼叫頻率;useAsync: true 啟用 I/O 完成通知埠,避免執行緒池阻塞。
// 循序掃描:預讀優化
var seq = new FileStream("big.log", FileMode.Open, FileAccess.Read, FileShare.Read,
65536, FileOptions.SequentialScan);
// 隨機存取:關閉預讀
var rnd = new FileStream("index.dat", FileMode.Open, FileAccess.Read, FileShare.Read,
4096, FileOptions.RandomAccess);
// 刪除時自動清理
var temp = new FileStream("temp.tmp", FileMode.CreateNew, FileAccess.ReadWrite,
FileShare.None, 4096, FileOptions.DeleteOnClose);
| 陷阱 | 後果 | 正確做法 |
|---|---|---|
| 未使用 using / try-finally | 檔案鎖定不釋放,後續無法存取 | 永遠用 using 區塊包裹 |
| 假設 Read 一次讀滿 | 網路/管道/檔案結尾可能讀不滿 | 迴圈累加直到讀滿或用 ReadExactlyAsync |
| 文字檔直接用 FileStream 讀寫 | 編碼錯誤、換行符號跨平台問題 | 文字用 StreamReader/Writer,二進位用 FileStream |
| 大檔案一次性 ReadToEnd | 記憶體暴漲、L OH 壓力 | 分塊讀取、Stream 處理、MemoryMappedFile |
| 忽略 FileShare 導致共用違規 | 多程序/執行緒無法同時讀取 | 預設給 FileShare.Read,日誌給 FileShare.ReadWrite |
FileStream 是 .NET 檔案 I/O 的基石,掌握其隨機存取、位元組操作、非同步模式與共用控制,是處理高效能、大檔案、二進位協定、嵌入式儲存等進階場景的必備技能。記住:文字用 StreamReader/Writer,二進位與隨機存取用 FileStream。