CodeGym /課程 /C# SELF /捕捉檔案例外 ( try-catch)...

捕捉檔案例外 ( try-catch)

C# SELF
等級 38 , 課堂 1
開放

1. 介紹

檔案操作幾乎總是會遇到程式外部狀況:檔案可能被刪除、移動、被其他程式鎖定、使用者突然沒有權限或磁碟沒空間。這些情況都可能導致例外 — 一種特殊情況,會中斷程式執行並“拋出”一個例外物件(Exception)。如果不捕捉並處理這類例外,程式會以錯誤結束,並向使用者顯示嚇人的紅色錯誤訊息(或者更糟——默默崩潰)。

在 C# 裡處理這類情況會用到 try-catch 區塊(俗稱「錯誤陷阱」)。它不只是用來「抓到」錯誤,還能讓你決定接下來怎麼做:顯示友善訊息、提示選擇其他檔案、把錯誤寫入日誌或是重試操作。

在實際應用中

如果你在寫一個命令列計算機,或許可以不處理檔案錯誤。但如果是企業文件處理程式或儲存進度的遊戲,不處理這些錯誤就像在走鋼索卻沒裝安全帶:遲早會出事。

2. 回顧例外處理

基本語法 try-catch

在進入具體的檔案場景前,回顧一下 try-catch 的基本語法(我們在例外相關講義中已經見過):


try
{
    // 這裡是可能會「拋出」例外的程式碼
}
catch (Exception ex)
{
    // 這裡我們捕捉所有可能的例外... 但最好別這麼做!
    Console.WriteLine("發生了問題: " + ex.Message);
}

try 內放潛在危險的程式碼,在 catch 內處理如果出錯要怎麼做。

程式設計師的笑話:「try-catch 就像是錯誤的隱形帽。錯誤存在,但你看不到它!」

檔案相關的例外

當透過 .NET 做檔案操作時,常會遇到在創建流、讀寫時拋出的例外。以下是常見情況與對應的例外類型:

  • 找不到檔案 → FileNotFoundException
  • 沒有存取檔案/目錄的權限 → UnauthorizedAccessException
  • 路徑問題(例如不允許的字元、路徑過長) → PathTooLongException, ArgumentException
  • 檔案被其他程序使用 → IOException
  • 磁碟空間不足 → IOException

大多數檔案操作相關的例外都是繼承自 IOException 的派生類。它們都繼承自基本型別 System.Exception

3. 實作:捕捉並處理檔案操作錯誤

我們來看幾個典型案例,假設我們的「正在開發的應用」嘗試從檔案讀取一條問候語,處理它並顯示給使用者。這裡會用 try-catch 做錯誤檢查。

範例 1:處理「找不到檔案」


string filePath = "hello.txt";

try
{
    string greeting = File.ReadAllText(filePath);
    Console.WriteLine("檔案內容: " + greeting);
}
catch (FileNotFoundException ex)
{
    Console.WriteLine("找不到檔案!請確認檔案 " + filePath + " 是否存在。");
    // 我們也可以輸出詳細資訊
    Console.WriteLine("技術細節: " + ex.Message);
}

如果檔案 "hello.txt" 不存在,程式不會當掉,而是輸出友善提示。就這麼簡單讓程式對使用者的「笨拙操作」更有韌性。

範例 2:權限被拒

情況複雜一點:檔案存在,但我們沒權限讀取(例如有人故意只給寫入權限,或檔案放在受保護的目錄)。


try
{
    string secret = File.ReadAllText("C:\\Windows\\System32\\config.txt");
}
catch (UnauthorizedAccessException ex)
{
    Console.WriteLine("無法存取檔案!試著以管理員身分執行程式。");
    Console.WriteLine("技術原因: " + ex.Message);
}

範例 3:一般的 IOException

有些錯誤可能是鎖定衝突(例如其他程序正在使用該檔案)、磁碟空間不足或硬體問題:


try
{
    File.WriteAllText("important.txt", "重要資訊!");
}
catch (IOException ex)
{
    Console.WriteLine("檔案操作發生錯誤:很可能是被其他程式使用或磁碟空間不足。");
    Console.WriteLine("技術原因: " + ex.Message);
}

4. 捕捉多個例外:選擇性處理

有時候你要針對不同例外做不同處理。在 .NET 裡可以寫多個 catch 區塊——要從更具體的例外寫到更通用的(否則編譯器會抱怨):


try
{
    string content = File.ReadAllText("file.txt");
    Console.WriteLine(content);
}
catch (FileNotFoundException ex)
{
    Console.WriteLine("找不到檔案。");
}
catch (UnauthorizedAccessException ex)
{
    Console.WriteLine("無權限存取檔案!");
}
catch (IOException ex)
{
    Console.WriteLine("其他輸入/輸出錯誤: " + ex.Message);
}

重要:如果把 catch (Exception ex) 放在最前面,後面的區塊就沒意義了,因為基類會先捕捉到一切!

5. 巢狀 try-catch 與重試機制

有時你不只想處理錯誤,還想給使用者機會「修正」——例如提示輸入存在的檔案路徑:


string filePath;
string content;
int attempts = 0;
const int maxAttempts = 3;

do
{
    Console.Write("請輸入檔案路徑: ");
    filePath = Console.ReadLine();

    try
    {
        content = File.ReadAllText(filePath);
        Console.WriteLine("檔案內容:\n" + content);
        break;
    }
    catch (FileNotFoundException)
    {
        Console.WriteLine("找不到檔案!請再試一次。");
    }
    catch (UnauthorizedAccessException)
    {
        Console.WriteLine("無法存取檔案!請試試其他檔案。");
    }
    attempts++;
}
while (attempts < maxAttempts);

if (attempts == maxAttempts)
    Console.WriteLine("嘗試次數過多。");

這段程式碼就是個小小的「使用者友善介面」,幫助忘記檔案放哪裡的使用者。

6. 常見錯誤與注意事項:從懶惰到有意識

新手(甚至有經驗的開發者)常犯的一個錯誤是把所有例外都抓住,寫成 catch (Exception) 然後只輸出「發生錯誤!」而不追根究柢。這種做法有幾個問題:第一,它會掩蓋商業邏輯上的真實錯誤。第二,非檔案相關的錯誤(例如程式碼打錯或數學錯誤)會被吞掉,找到真正原因會變得很難。

更好的做法是只捕捉那些你能有意義處理的錯誤。如果不確定是什麼錯誤,寧可讓它「炸掉」——也就是不要捕捉,讓應用崩潰,這樣你可以看到呼叫堆疊來找 bug。

注意:有些例外可能會帶有內部原因(InnerException)。在寫錯誤日誌時分析它們能提供更詳細的診斷資訊。

另一個要點是:如果在 catch 後程式無法繼續(例如無法打開主要設定檔),可以用 return 結束執行,或者重新拋出例外(throw;),不要讓程式變成功能不全的「殭屍程式」。

2
任務
C# SELF, 等級 38, 課堂 1
上鎖
處理多個例外狀況時寫入檔案
處理多個例外狀況時寫入檔案
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION