1. 介紹
直接操作流(StreamReader, StreamWriter, FileStream)非常有用,特別是當你需要在低層級控制讀寫流程時:例如,分塊寫入或分段處理大型檔案。
但在實務上,很多情境只是想知道:「這個檔案存在嗎?」「把檔案從這裡複製到那裡」「刪除檔案」「取得資料夾中所有 .txt 檔案的清單」等等。針對這類工作,Microsoft 提供了兩個通用工具:靜態類別 File 和 Directory。靜態的意思是你不需要建立實例,直接用類別名稱呼叫方法。
生活類比
如果流是你拿著鉛筆,一筆一畫地在紙上寫字,那 File 和 Directory 就像你的桌子和抽屜:你可以「瞬間」打開一個抽屜(Directory),從裡面拿出一張紙(File.ReadAllText),丟掉那張紙(File.Delete),甚至把整個抽屜搬到房間另一邊(Directory.Move)。簡單的事就用簡單的方法。
2. 類別 File:是什麼、有什麼用
File 提供了一組方便的靜態方法,涵蓋常見的檔案操作。
最常用的方法
| 方法 | 說明 |
|---|---|
|
檢查路徑上是否存在檔案 |
|
將整個檔案讀成文字 |
|
把檔案的所有行讀成陣列 |
|
覆寫檔案,寫入文字 |
|
在檔案末尾追加文字 |
|
複製檔案 |
|
刪除檔案 |
|
移動或重新命名檔案 |
|
打開流以進行複雜操作 |
快速範例:檢查檔案並讀取
string filePath = "data.txt";
if (File.Exists(filePath))
{
string content = File.ReadAllText(filePath);
Console.WriteLine("檔案內容:");
Console.WriteLine(content);
}
else
{
Console.WriteLine("找不到檔案!");
}
看到了嗎?對於簡單情況完全不用手動管理流!
3. 類別 Directory:管理資料夾不再痛苦
如果 File 處理單一檔案,那 Directory 就是處理資料夾(目錄)。
主要任務
| 方法 | 說明 |
|---|---|
|
檢查資料夾是否存在 |
|
建立資料夾(包含所有中間資料夾) |
|
刪除資料夾(可包含子目錄) |
|
取得資料夾中的檔案清單 |
|
取得子目錄清單 |
|
移動或重新命名資料夾 |
|
取得應用程式的當前工作目錄 |
範例:建立資料夾並把檔案存進去
string dirPath = "Results";
if (!Directory.Exists(dirPath))
{
Directory.CreateDirectory(dirPath);
Console.WriteLine("資料夾 'Results' 已建立。");
}
string filePath = Path.Combine(dirPath, "summary.txt");
File.WriteAllText(filePath, "最終資料:...");
Console.WriteLine($"檔案 {filePath} 已寫入。");
4. File 和 Directory 的典型使用情境
若只看到基本方法可能覺得無聊!我們用一個簡單的應用場景來展示它們的用法(假設我們做一個簡單的待辦清單系統 todo-list,結果儲存在檔案中)。
儲存資料到檔案(覆寫舊檔)
// 將待辦事項儲存到檔案
string[] todos = { "買麵包", "打電話給醫生", "做 C# 的作業" };
string filePath = "todo.txt";
File.WriteAllLines(filePath, todos);
Console.WriteLine("待辦清單已儲存。");
從檔案載入資料
// 若檔案存在則載入任務
if (File.Exists(filePath))
{
string[] loadedTodos = File.ReadAllLines(filePath);
Console.WriteLine("你的待辦清單:");
foreach (var task in loadedTodos)
{
Console.WriteLine("- " + task);
}
}
else
{
Console.WriteLine("你還沒有待辦清單。");
}
新增任務(不覆寫檔案)
string newTask = "帶狗去散步";
File.AppendAllText(filePath, newTask + Environment.NewLine);
Console.WriteLine("任務已加入!");
複製與備份檔案
string backupPath = "todo_backup.txt";
File.Copy(filePath, backupPath, overwrite: true);
Console.WriteLine("待辦清單備份已建立。");
移動(或重新命名)檔案
string archivePath = "todo_archive.txt";
File.Move(filePath, archivePath);
Console.WriteLine("待辦清單已封存(重新命名)。");
刪除檔案
if (File.Exists(archivePath))
{
File.Delete(archivePath);
Console.WriteLine("封存已刪除 — 釋放空間!");
}
5. 資料夾操作:範例
建立目錄階層
string path = Path.Combine("Reports", "2024", "June");
Directory.CreateDirectory(path);
Console.WriteLine($"資料夾 {path} 已建立(包含中間資料夾)。");
取得檔案與資料夾清單
string dirPath = "Reports";
if (Directory.Exists(dirPath))
{
string[] files = Directory.GetFiles(dirPath);
Console.WriteLine("資料夾中的檔案:");
foreach (var file in files)
{
Console.WriteLine(file);
}
string[] subDirs = Directory.GetDirectories(dirPath);
Console.WriteLine("子目錄:");
foreach (var dir in subDirs)
{
Console.WriteLine(dir);
}
}
按遮罩過濾檔案(只要 .txt)
string[] txtFiles = Directory.GetFiles(dirPath, "*.txt");
Console.WriteLine("只有 .txt 檔案:");
foreach (var file in txtFiles)
{
Console.WriteLine(file);
}
遞迴遍歷(所有子目錄中的檔案)
string[] allFiles = Directory.GetFiles(dirPath, "*.*", SearchOption.AllDirectories);
Console.WriteLine("所有子目錄中的檔案:");
foreach (var file in allFiles)
{
Console.WriteLine(file);
}
移動與刪除目錄
string from = "OldReports";
string to = "Archive/OldReports";
if (Directory.Exists(from))
{
Directory.Move(from, to);
Console.WriteLine($"資料夾 {from} 已移動到 {to}");
}
if (Directory.Exists(to))
{
Directory.Delete(to, recursive: true); // true: 刪除內部所有內容
Console.WriteLine($"資料夾 {to} 已刪除(含所有內容)。");
}
6. 有用的小細節
與路徑整合:類別 Path
處理檔案與資料夾時常需要組合完整路徑、合併目錄與檔名、解析副檔名、檢查允許的字元。這些都可以用輔助類別 Path。
範例
string folder = "Results";
string filename = "week1.txt";
string fullPath = Path.Combine(folder, filename); // 安全的合併方式!
Console.WriteLine(fullPath); // "Results/week1.txt"(或在 Windows 上是 "\")
- 取得檔案副檔名: Path.GetExtension(fullPath)
- 取得不含路徑的檔名: Path.GetFileName(fullPath)
用 Path.Combine 代替字串串接——對跨平台應用更安全。
「一次完成」的方法 vs 流式變體
很多 File 和 Directory 的方法(例如 File.ReadAllText, File.WriteAllText, Directory.GetFiles)會把工作一次做完:讀取/寫入/取得檔案清單一次性完成。這非常方便,但不適合超大檔案或超大目錄,可能會耗盡記憶體。處理 GB 級資料時請改用流類別(StreamReader, StreamWriter, FileStream 等)或分段處理。
何時用 File/Directory,何時用流類別
| 情境 | 使用什麼 |
|---|---|
| 需要檢查檔案/資料夾是否存在 | |
| 讀/寫整個小檔案 | |
| 在檔案末尾加入文字 | |
| 取得目錄中的檔案清單 | |
| 複製、刪除、移動檔案 | |
| 複製/刪除整個資料夾 | Directory.Delete/Move/Copy(Copy 通常需第三方套件) |
| 分段處理非常大的檔案 | 使用流類別(StreamReader, FileStream) |
實務意義與應用場景
- 快速載入/儲存設定、設定檔、JSON/XML 檔案。
- 記錄系統(將 log 寫到磁碟)。
- 簡單的備份工具與資料遷移。
- 掃描多媒體、照片、文件的資料夾。
- 使用者情境:載入範本、匯出/匯入、產生報表等。
面試中的實作題也常會用到這些類別:例如「實作一個函式計算資料夾中所有 .txt 檔案的總大小」、「把檔案備份到另一個資料夾」等等。
視覺速查:什麼情況用哪個方法
graph TD
A[你想做什麼?]
A -->|檢查是否存在| B[File.Exists 或 Directory.Exists]
A -->|整個讀/寫檔案| C[File.ReadAllText/WriteAllText]
A -->|新增資料到檔案| D[File.AppendAllText]
A -->|處理資料夾| E[Directory.CreateDirectory, GetFiles, GetDirectories]
A -->|複製/刪除/移動檔案| F[File.Copy/Delete/Move]
A -->|複製/刪除整個資料夾| G[Directory.Delete/Move]
7. 特性與常見錯誤
存在檢查與競態條件。即使先檢查了檔案/資料夾存在,另一個程序也可能在你實際操作前改變它。即便已檢查,還是要用 try-catch 包住實際操作!
存取權限。如果應用沒有讀/寫/刪除權限,方法會丟出 UnauthorizedAccessException。
路徑太長。舊版 Windows 常見的最大路徑長度是 260 字元;在 .NET 9 情況有所改善,但仍要小心。
錯誤處理。像 File.ReadAllText 或 Directory.GetFiles 這類方法遇到錯誤會直接丟例外:檔案/資料夾不存在就會失敗。把呼叫包在 try-catch 裡,或是先檢查存在性再操作。
GO TO FULL VERSION