首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# FileStream 完全指南:隨機存取、位元組操作與高效能檔案處理實戰

     編輯:關於C語言

為什麼需要 FileStream?

FileStream 是 .NET 直接操作作業系統檔案控制代碼的核心類別,提供位元組級別的隨機存取能力。雖然 StreamReader/Writer 處理文字更方便,但以下場景必須使用 FileStream:

  • 二進位檔案(圖片、影音、壓縮檔、資料庫頁面)
  • 隨機存取:直接跳轉至檔案任意位置讀寫(如資料庫索引、斷點續傳)
  • 大檔案分塊處理:避免一次性載入記憶體造成 OOM
  • 精確控制檔案指標、鎖定區段、非同步 I/O 等底層行為

核心建構子與枚舉詳解

FileMode:決定開啟/建立行為

枚舉值檔案存在檔案不存在典型用途
CreateNew拋出例外建立新檔獨佔建立,防止覆寫
Create覆寫(截斷)建立新檔最常用,確保乾淨狀態
Open開啟現有拋出例外唯讀或讀寫現有檔
OpenOrCreate開啟現有建立新檔設定檔、快取檔
Truncate清空內容拋出例外保留建立時間,重置內容
Append指標移至末尾建立新檔日誌記錄、追加寫入

FileAccess:宣告讀寫意圖

  • Read:唯讀,允許多人同時開啟
  • Write:唯寫,通常搭配 Append
  • ReadWrite:讀寫皆可,預設值

FileShare:控制並發存取(常被忽視但關鍵)


// 允許其他程序同時讀取,但禁止寫入
var fs = new FileStream("data.bin", FileMode.Open, FileAccess.Read, FileShare.Read);

隨機存取核心:Seek 方法與檔案指標

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
    }
}

進階主題:非同步 I/O 與效能優化

非同步讀寫(.NET Core / .NET 5+ 強烈建議)


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 完成通知埠,避免執行緒池阻塞。

記憶體對齊與 FileOptions


// 循序掃描:預讀優化
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。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved