CodeGym /Kursy /C# SELF /Przechwytywanie wyjątków plikowych (

Przechwytywanie wyjątków plikowych ( try-catch)

C# SELF
Poziom 38 , Lekcja 1
Dostępny

1. Wprowadzenie

Operacje na plikach prawie zawsze są związane z okolicznościami zewnętrznymi względem programu: plik może zostać usunięty, przeniesiony, zablokowany przez inny program, nagle użytkownik może stracić uprawnienia albo zabraknąć miejsca na dysku. To wszystko może prowadzić do wyjątków — specjalnych sytuacji, kiedy wykonanie programu zostaje przerwane i "wyrzucany" jest obiekt wyjątku (Exception). Jeśli nie przechwycisz i nie obsłużysz takiego wyjątku, twój program zakończy się błędem i pokaże użytkownikowi straszny czerwony tekst w konsoli (albo, co gorsza — cicho upadnie).

W C# do obsługi takich sytuacji używa się bloku try-catch (albo, prościej, "pułapka na błędy"). Pozwala on nie tylko "złapać" błąd, ale też spokojnie zdecydować, co dalej zrobić: pokazać przyjazny komunikat, zaproponować wybór innego pliku, zapisać błąd do loga albo po prostu spróbować ponownie.

W prawdziwych aplikacjach

Jeśli piszesz konsolowy kalkulator, to pewnie możesz obyć się bez łapania błędów przy pracy z plikami. Ale jeśli tworzysz program do przetwarzania dokumentów w firmie albo grę zapisującą stan — nieobsługiwanie takich błędów to jak chodzenie po linie bez zabezpieczenia: prędzej czy później coś się wydarzy.

2. Przypomnienie pracy z wyjątkami

Podstawowa składnia try-catch

Zanim przejdziemy do konkretnych sytuacji z plikami, przypomnijmy podstawową składnię konstrukcji try-catch (którą już spotykaliśmy na wykładach o wyjątkach):


try
{
    // Tutaj kod, który może "wyrzucić" wyjątek
}
catch (Exception ex)
{
    // Tutaj łapiemy wszystkie możliwe wyjątki... Ale lepiej tak nie robić!
    Console.WriteLine("Coś poszło nie tak: " + ex.Message);
}

Wewnątrz try piszemy potencjalnie niebezpieczny kod, a w catch — co robić, jeśli coś pójdzie nie tak.

Żart programisty: "try-catch — to taki cyfrowy odpowiednik czapki-niewidki na błędy. Błąd jest, ale go nie widzisz!"

Wyjątki plikowe

Kiedy pracujesz z plikami przez .NET, najczęściej spotykasz wyjątki — na przykład przy tworzeniu strumienia, odczycie lub zapisie. Oto kilka typowych scenariuszy i związanych z nimi wyjątków:

  • Plik nie znaleziony → FileNotFoundException
  • Brak dostępu do pliku/katalogu → UnauthorizedAccessException
  • Problemy ze ścieżką (np. niedozwolone znaki, zbyt długa ścieżka) → PathTooLongException, ArgumentException
  • Plik jest już używany przez inny proces → IOException
  • Brak miejsca na dysku → IOException

Najczęściej przy operacjach plikowych spotykamy pochodne IOException. Wszystkie one dziedziczą od bazowego typu System.Exception.

3. Praktyka: łapanie i obsługa błędów przy pracy z plikami

Spójrzmy na typowe przypadki na przykładach naszego "rozwijającego się" aplikacji: załóżmy, że próbujemy odczytać powitanie z pliku, przetworzyć je i wypisać użytkownikowi. Dodamy tu sprawdzanie błędów za pomocą try-catch.

Przykład 1: Obsługa "plik nie znaleziony"


string filePath = "hello.txt";

try
{
    string greeting = File.ReadAllText(filePath);
    Console.WriteLine("Zawartość pliku: " + greeting);
}
catch (FileNotFoundException ex)
{
    Console.WriteLine("Plik nie znaleziony! Sprawdź, czy plik " + filePath + " istnieje.");
    // Możemy dodatkowo wypisać szczegóły
    Console.WriteLine("Szczegóły techniczne: " + ex.Message);
}

Jeśli plik "hello.txt" nie istnieje, program nie zakończy się błędem, tylko wypisze przyjazny komunikat. Tak po prostu czynimy program odpornym na "głupie" błędy użytkownika.

Przykład 2: Brak uprawnień

Weźmy trudniejszą sytuację: plik istnieje, ale nie mamy praw do jego odczytu (np. ktoś ustawił tylko prawa zapisu albo plik leży w chronionym folderze).


try
{
    string secret = File.ReadAllText("C:\\Windows\\System32\\config.txt");
}
catch (UnauthorizedAccessException ex)
{
    Console.WriteLine("Brak dostępu do pliku! Spróbuj uruchomić program jako administrator.");
    Console.WriteLine("Przyczyna techniczna: " + ex.Message);
}

Przykład 3: Ogólne IOException

Niektóre błędy mogą być związane z konfliktem blokad (np. inny proces trzyma plik otwarty), brakiem miejsca na dysku albo problemami sprzętowymi:


try
{
    File.WriteAllText("important.txt", "Ważna informacja!");
}
catch (IOException ex)
{
    Console.WriteLine("Błąd przy pracy z plikiem: najprawdopodobniej jest używany przez inny program albo na dysku brak miejsca.");
    Console.WriteLine("Przyczyna techniczna: " + ex.Message);
}

4. Przechwytywanie wielu wyjątków: selektywna obsługa

Czasami trzeba reagować różnie na różne typy wyjątków. W .NET można podać kilka bloków catch — od bardziej specyficznych do ogólnych (inaczej kompilator urządzi twojemu kodowi głośny włoski strajk).


try
{
    string content = File.ReadAllText("file.txt");
    Console.WriteLine(content);
}
catch (FileNotFoundException ex)
{
    Console.WriteLine("Plik nie znaleziony.");
}
catch (UnauthorizedAccessException ex)
{
    Console.WriteLine("Brak dostępu do pliku!");
}
catch (IOException ex)
{
    Console.WriteLine("Inny błąd wejścia-wyjścia: " + ex.Message);
}

Ważne: jeśli postawisz catch (Exception ex) pierwszym, pozostałe bloki stracą sens, bo typ bazowy przechwyci wszystko!

5. Zagnieżdżone try-catch i ponowne próby

Czasem chcesz nie tylko obsłużyć błąd, ale i dać użytkownikowi szansę "naprawić się" — na przykład zaproponować wpisanie ścieżki do istniejącego pliku:


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

do
{
    Console.Write("Wpisz ścieżkę do pliku: ");
    filePath = Console.ReadLine();

    try
    {
        content = File.ReadAllText(filePath);
        Console.WriteLine("Zawartość pliku:\n" + content);
        break;
    }
    catch (FileNotFoundException)
    {
        Console.WriteLine("Plik nie znaleziony! Spróbuj jeszcze raz.");
    }
    catch (UnauthorizedAccessException)
    {
        Console.WriteLine("Brak dostępu do pliku! Spróbuj innego pliku.");
    }
    attempts++;
}
while (attempts < maxAttempts);

if (attempts == maxAttempts)
    Console.WriteLine("Zbyt dużo nieudanych prób.");

Ten kod to mały "przyjazny interfejs" dla użytkownika, który zapomniał, gdzie zapisał plik.

6. Typowe błędy i cechy: od lenistwa do świadomości

Bardzo częsty błąd początkujących (a nawet doświadczonych deweloperów) — łapać wszystkie wyjątki po kolei, pisać po prostu catch (Exception) i wypisywać "Wystąpił błąd!", nie zastanawiając się nad przyczynami. Takie podejście jest złe z kilku powodów. Po pierwsze, ukrywa rzeczywiste niedociągnięcia w logice biznesowej aplikacji. Po drugie, inne, niezwiązane z plikami błędy (np. literówki w kodzie albo błąd matematyczny) mogą zostać przypadkowo przeoczone, i znalezienie prawdziwej przyczyny potrwa dużo dłużej.

Znacznie lepiej — jawnie łapać tylko te błędy, które potrafisz sensownie obsłużyć. Jeśli nie wiadomo, jaki błąd zaszedł, lepiej pozwolić mu "upaść" — czyli nie łapać go wcale: niech aplikacja padnie, ale zobaczysz stack trace i zrozumiesz, co trzeba poprawić.

Cecha: Niektóre wyjątki mogą mieć zagnieżdżone przyczyny (InnerException). Warto je analizować dla dokładniejszej diagnostyki, zwłaszcza gdy piszesz logi błędów.

Jeszcze jeden niuans — jeśli po bloku catch dalsze działanie programu jest niemożliwe (np. nie udało się otworzyć głównego pliku konfiguracyjnego), możesz zakończyć działanie przez return albo nawet wyrzucić wyjątek ponownie (throw;), żeby nie tworzyć "zombie-aplikacji" z połową funkcji.

2
Zadanie
C# SELF, poziom 38, lekcja 1
Niedostępne
Obsługa wielu wyjątków podczas zapisu do pliku
Obsługa wielu wyjątków podczas zapisu do pliku
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION