前言
檔案系統操作的基礎在於路徑字串處理。.NET 提供 System.IO.Path 靜態類別,以跨平台方式處理路徑合併、分割、驗證、暫存路徑等。本篇涵蓋路徑判斷、特定部分擷取、合併、系統資料夾取得、相對/絕對路徑轉換,以及三大常用檔案對話框 (FolderBrowserDialog、OpenFileDialog、SaveFileDialog) 完整用法。
一、Path 類別核心操作
1. 判斷路徑合法性
bool IsValidPath(string path)
{
try
{
// 嘗試取得完整路徑,若包含非法字元會拋 ArgumentException
string full = Path.GetFullPath(path);
// 額外檢查非法字元 (含萬用字元 * ? 除外)
foreach (char c in Path.GetInvalidPathChars())
if (path.IndexOf(c) >= 0) return false;
return true;
}
catch { return false; }
}
2. 判斷路徑類型:檔案 vs 目錄
// 方法一:實際存在時
bool isDir = Directory.Exists(path);
bool isFile = File.Exists(path);
// 方法二:不存在時,依字串特徵判斷
bool LooksLikeDirectory(string path)
{
if (string.IsNullOrEmpty(path)) return false;
string fileName = Path.GetFileName(path);
return string.IsNullOrEmpty(fileName) || fileName.EndsWith("."); // 結尾無檔名或以 . 結尾
}
3. 擷取路徑特定部分
| 方法 | 輸入範例 | 輸出範例 | 說明 |
| GetDirectoryName | C:\Dir\Sub\file.txt | C:\Dir\Sub | 目錄部分 |
| GetFileName | C:\Dir\Sub\file.txt | file.txt | 檔名+副檔名 |
| GetFileNameWithoutExtension | C:\Dir\Sub\file.txt | file | 純檔名 |
| GetExtension | C:\Dir\Sub\file.txt | .txt | 副檔名 (含點) |
| GetPathRoot | C:\Dir\Sub\file.txt | C:\ | 根目錄/磁碟機 |
| ChangeExtension | (path, ".bak") | C:\Dir\Sub\file.bak | 變更副檔名 |
| HasExtension | file.txt | true | 是否有副檔名 |
4. 安全合併路徑 — Path.Combine
// 自動處理斜線、避免雙斜線、相對路徑正確合併
string p1 = Path.Combine(@"C:\Dir", "Sub", "file.txt"); // C:\Dir\Sub\file.txt
string p2 = Path.Combine(@"C:\Dir\", @"Sub\file.txt"); // C:\Dir\Sub\file.txt
string p3 = Path.Combine("SubDir", "file.txt"); // SubDir\file.txt (相對路徑)
string p4 = Path.Combine(@"C:\Dir", @"D:\Other\file.txt"); // D:\Other\file.txt (第二參數為絕對路徑時忽略第一參數)
5. 系統特殊資料夾路徑
// Environment.SpecialFolder 列舉
string desktop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); // C:\Users\John\Desktop
string myDocs = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); // C:\Users\John\Documents
string programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles); // C:\Program Files
string appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); // C:\Users\John\AppData\Roaming
string localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); // C:\Users\John\AppData\Local
string temp = Path.GetTempPath(); // C:\Users\John\AppData\Local\Temp\
string systemDir = Environment.SystemDirectory; // C:\Windows\System32
6. 絕對/相對路徑判斷與轉換
bool isAbsolute = Path.IsPathRooted(@"C:\Dir\file.txt"); // true
bool isRelative = Path.IsPathRooted(@"Sub\file.txt"); // false
// 相對路徑轉絕對 (依賴目前工作目錄)
string abs = Path.GetFullPath(@"Sub\file.txt"); // C:\Current\Work\Dir\Sub\file.txt
// 設定/取得目前工作目錄
Directory.SetCurrentDirectory(@"C:\New\Work\Dir");
string cwd = Directory.GetCurrentDirectory();
安全警告:使用相對路徑時,務必先設定確定的工作目錄,否則惡意使用者可透過 `..\..\Windows\System32` 存取系統檔案。
二、常用檔案/資料夾對話框
1. FolderBrowserDialog — 選擇資料夾
using (var dlg = new FolderBrowserDialog())
{
dlg.Description = "請選擇要備份的資料夾";
dlg.RootFolder = Environment.SpecialFolder.MyComputer; // 從「我的電腦」開始
dlg.ShowNewFolderButton = true; // 允許新建資料夾
dlg.SelectedPath = @"C:\Default\Path"; // 預設選取路徑
if (dlg.ShowDialog() == DialogResult.OK)
{
string selected = dlg.SelectedPath;
// 執行備份邏輯
}
}
2. OpenFileDialog — 開啟檔案
using (var dlg = new OpenFileDialog())
{
dlg.Title = "選擇要匯入的 CSV 檔案";
dlg.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
dlg.Filter = "CSV 檔案 (*.csv)|*.csv|文字檔 (*.txt)|*.txt|所有檔案 (*.*)|*.*";
dlg.FilterIndex = 1; // 預設選第一個篩選
dlg.Multiselect = true; // 允許多選
dlg.CheckFileExists = true; // 檔案不存在時警告
dlg.CheckPathExists = true;
dlg.ReadOnlyChecked = true; // 預設勾選唯讀
dlg.ShowReadOnly = true; // 顯示唯讀核取方塊
if (dlg.ShowDialog() == DialogResult.OK)
{
foreach (string file in dlg.FileNames)
{
// 處理每個選取檔案
}
}
}
3. SaveFileDialog — 另存新檔
using (var dlg = new SaveFileDialog())
{
dlg.Title = "匯出報表為 Excel";
dlg.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
dlg.Filter = "Excel 活頁簿 (*.xlsx)|*.xlsx|CSV 檔案 (*.csv)|*.csv";
dlg.FilterIndex = 1;
dlg.DefaultExt = "xlsx"; // 自動附加副檔名
dlg.AddExtension = true;
dlg.OverwritePrompt = true; // 檔案存在時詢問覆蓋
dlg.CreatePrompt = false; // 路徑不存在時不提示建立
dlg.FileName = $"Report_{DateTime.Now:yyyyMMdd}.xlsx"; // 預設檔名
if (dlg.ShowDialog() == DialogResult.OK)
{
string file = dlg.FileName;
// 執行匯出邏輯
}
}
對話框共用屬性速查
| 屬性 | OpenFileDialog | SaveFileDialog | FolderBrowserDialog |
| Title | ✓ | ✓ | ✓ (Description) |
| InitialDirectory | ✓ | ✓ | ✓ (RootFolder) |
| Filter / FilterIndex | ✓ | ✓ | ✗ |
| FileName / FileNames | ✓ | ✓ | ✗ (SelectedPath) |
| Multiselect | ✓ | ✗ | ✗ |
| CheckFileExists | ✓ | ✗ | ✗ |
| OverwritePrompt | ✗ | ✓ | ✗ |
| ShowReadOnly | ✓ | ✗ | ✗ |
| DefaultExt / AddExtension | ✗ | ✓ | ✗ |
三、路徑字串安全性檢查清單
- ✅ 使用
Path.Combine 而非字串連接
- ✅ 使用
Path.GetInvalidPathChars / GetInvalidFileNameChars 驗證使用者輸入
- ✅ 使用
Path.IsPathRooted 區分絕對/相對路徑
- ✅ 相對路徑前 鎖定工作目錄 (`Directory.SetCurrentDirectory`)
- ✅ 長路徑 (>260) 啟用
LongPathsEnabled 或 `\\?\` 前綴
- ✅ 跨平台路徑分隔符用
Path.DirectorySeparatorChar / Path.AltDirectorySeparatorChar
- ✅ 避免硬編碼 `C:\`、`D:\`,改用
Environment.GetFolderPath / Path.GetTempPath
四、Path 類別完整方法速查表
| 分類 | 方法 | 說明 |
| 路徑分割 | GetDirectoryName | 取得目錄路徑 |
| GetFileName | 取得檔名+副檔名 |
| GetFileNameWithoutExtension | 取得純檔名 |
| GetExtension | 取得副檔名 |
| GetPathRoot | 取得根目錄/磁碟機 |
| HasExtension | 判斷是否有副檔名 |
| IsPathRooted | 判斷絕對路徑 |
| GetFullPath | 相對轉絕對路徑 |
| 路徑合併/修改 | Combine | 安全合併多段路徑 |
| ChangeExtension | 變更副檔名 |
| GetTempPath | 取得暫存目錄 |
| GetTempFileName | 建立唯一暫存檔 |
| GetRandomFileName | 產生隨機檔名 |
| 驗證/字元 | GetInvalidPathChars | 非法路徑字元陣列 |
| GetInvalidFileNameChars | 非法檔名字元陣列 |
| PathSeparator | 路徑分隔字元 (;) |
| DirectorySeparatorChar | 目錄分隔字元 (\) |
| AltDirectorySeparatorChar | 替代分隔字元 (/) |
| VolumeSeparatorChar | 磁碟機分隔字元 (:) |