2012-09-12 11 views
14

Próbując odpowiedzieć na this question, zdziwiło mnie, że próba utworzenia nowego pliku, gdy ten plik już istnieje, nie generuje unikalnego typu wyjątku, ale po prostu wyrzuca ogólny IOException.Kody wyjątków lub wykrywanie wyjątku typu "plik już istnieje"

Po tym wszystkim zastanawiałem się, jak ustalić, czy IOException jest wynikiem istniejącego pliku lub innego błędu we/wy.

Wyjątek ma HResult, ale ta właściwość jest chroniona, a zatem niedostępna dla mnie.

Jedyny inny sposób, jaki widzę, to wzór pasujący do ciągu wiadomości, który wydaje się okropny.

przykład:

try 
{ 
    using (var stream = new FileStream("C:\\Test.txt", FileMode.CreateNew)) 
    using (var writer = new StreamWriter(stream)) 
    { 
     //write file 
    } 
} 
catch (IOException e) 
{ 
    //how do I know this is because a file exists? 
} 
+6

Dlaczego nie można po prostu sprawdzić, czy plik istnieje? POCAŁUNEK. –

+3

Ponieważ system plików jest z natury niestabilny. Pliki można tworzyć w dowolnym momencie (nie tylko przeze mnie). – GazTheDestroyer

+1

Przesyłanie wielu błędów do jednego wyjątku bez możliwości ich rozróżnienia jest prawdopodobnie najgorszą cechą projektu .NET Framework. Masz taki sam problem z dyskiem pełnym, nie znaleziono ścieżki sieciowej itp. Wyjątki. Nawet jeśli dostaniesz kod HResult, jeśli twój kod musi działać również pod Mono w Linuksie, to nie jest to obsługiwane. – jimvfr

Odpowiedz

7
try 
{ 
    using (var stream = new FileStream("C:\\Test.txt", FileMode.CreateNew)) 
    using (var writer = new StreamWriter(stream)) 
    { 
     //write file 
    } 
} 
catch (IOException e) 
{ 
    var exists = File.Exists(@"C:\Text.text"); // =) 
} 

nie działa dla plików tymczasowych itp, które mogły zostać ponownie usunięte.

+0

Durr, całkiem oczywiste, dzięki! – GazTheDestroyer

+4

To nie jest metoda deterministyczna: plik może zostać usunięty po zgłoszeniu wyjątku, ale przed sprawdzeniem w bloku catch. – SerG

+1

Dlatego właśnie powiedziałem: "Nie będzie działać dla plików tymczasowych itp., Które mogły zostać usunięte ponownie" – jgauffin

0

Należy użyć

FileMode.Create 

zamiast

FileMode.CreateNew 

Będzie nadpisać plik, jeśli jej już istnieje.

+2

Nie chcę nadpisywać jeśli istnieje. – GazTheDestroyer

0

Nie możesz. Niestety, wyjątki IOExceptions nie są określone z jakiegoś powodu, poza moim zrozumieniem w środowisku .NET.

Jednak w przypadku tworzenia nowego pliku powszechną praktyką jest sprawdzenie, czy plik istnieje wcześniej. Podobnie jak:

 try 
     { 
      if (File.Exists("C:\\Test.txt")) 
      { 
       //write file 

       using (var stream = new FileStream("C:\\Test.txt", FileMode.CreateNew)) 
       using (var writer = new StreamWriter(stream)) 
       { 
        //The actual writing of file 

       } 

      } 
     } 
     catch (IOException ex) 
     { 
      //how do I know this is because a file exists? 
      Debug.Print(ex.Message); 
     } 

Być może nie jest to odpowiedź, której szukałeś. Ale c'est ca.

+0

Problem: Inny proces * może * utworzyć plik pomiędzy sprawdzeniem, które istnieje i próbować go utworzyć. Innym rozwiązaniem może być sprawdzenie, czy plik istnieje * po * tworzenie się nie powiedzie. –

+0

Prawda. Dobra decyzja. –

0

To nie jest 100% niezawodny (istnieją inne powody, dla IOException), ale można przynajmniej wykluczyć wszystkie pochodzące rodzajów wyjątek:

try 
{ 
    ... 
} 
catch(IOException e) 
{ 
    if (e is UnauthorizedAccessException) throw; 
    if (e is DirectoryNotFoundException) throw; 
    if (e is PathTooLongException) throw; 
    // etc for other exceptions derived from IOException 

    ... assume file exists 
} 

lub równoważne:

try 
{ 
    ... 
} 
catch(UnauthorizedAccessException) 
{ 
    throw; 
} 
catch(DirectoryNotFoundException) 
{ 
    throw; 
} 
catch(PathTooLongException) 
{ 
    throw; 
} 
catch(IOException e) 
{ 
    ... assume file exists 
} 

chodzi o połączone pytanie, po prostu sprawdzę istnienie, zachęcam użytkownika do nadpisania, a następnie użyj OpenOrCreate, aby nadpisać, jeśli istnieje. Myślę, że większość aplikacji działa w ten sposób, nawet jeśli istnieje teoretyczne ryzyko nadpisania pliku, który został utworzony właśnie w niewłaściwym momencie.

5

Możesz umieścić ten warunek w wyciągu catch dla IOException: if(ex.Message.Contains("already exists")) { ... }. To hack, ale zadziała dla wszystkich przypadków, gdy plik istnieje, nawet pliki tymczasowe i tym podobne.

2

Aby zmodyfikować @jgauffin w C# 6, można użyć File.Exists wewnątrz klauzuli when aby uniknąć wprowadzania blok catch a zatem behaving more like an actual dedicated exception:

try 
{ 
    using (var stream = new FileStream("C:\\Test.txt", FileMode.CreateNew)) 
    using (var writer = new StreamWriter(stream)) 
    { 
     //write file 
    } 
} 
catch (IOException e) when (File.Exists(@"C:\Text.text")) 
{ 
    //... 
} 
2

Podczas próby utworzenia nowego pliku i już istnieje IOException będzie miał Hresult = 0x80070050 (-2147024816).

więc kod może wyglądać następująco:

try 
{ 
    using (var stream = new FileStream("C:\\Test.txt", FileMode.CreateNew)) 
    using (var writer = new StreamWriter(stream)) 
    { 
     //write file 
    } 
} 
catch (IOException e) 
{ 
    if (e.HResult == -2147024816) 
    { 
     // File already exists. 
    } 
} 
+0

HResult był chroniony (patrz mój trzeci akapit), więc to wygląda na ważne tylko w .Net4.5, ale przydatne, aby wiedzieć, że jest już dostępny, dziękuję. – GazTheDestroyer

Powiązane problemy