2012-09-12 58 views
14

在試圖回答this question時,我驚訝地發現當該文件已存在時嘗試創建新文件不會拋出唯一的異常類型,它只會拋出通用的IOException異常代碼或檢測到「文件已存在」類型異常

因此我想知道如何確定IOException是現有文件的結果還是其他一些IO錯誤。

異常有一個HResult,但此屬性是受保護的,因此對我無效。

我能看到的唯一的另一種方式是模式匹配消息字符串,感覺很糟糕。

例如:

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

爲什麼你不只是檢查,看看文件是否存在?吻。 –

+3

由於文件系統固有地不穩定。文件可以隨時創建(不僅僅是我)。 – GazTheDestroyer

+1

將多個錯誤集成爲一個異常,無法區分它們可能是.NET框架設計的最糟糕的特性。您在磁盤已滿,未找到網絡路徑等方面存在相同的問題。IOException。即使您獲得HResult代碼,如果您的代碼也需要在Linux上的Mono下運行,那麼不支持 – jimvfr

回答

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"); // =) 
} 

不會爲臨時文件等,這可能已再次刪除工作。

+0

杜爾,真的很明顯,謝謝! – GazTheDestroyer

+4

這不是確定性的方式:在拋出異常之後但在catch塊中檢入之前,文件可能被刪除。 – SerG

+1

這就是爲什麼我說'不適用於可能已被刪除的臨時文件等' – jgauffin

0

,您應該使用的

FileMode.Create 

代替

FileMode.CreateNew 

它會覆蓋一個文件,如果它已經存在。

+2

我不想覆蓋它是否存在。 – GazTheDestroyer

0

你不能。不幸的是,由於某些原因,在.NET框架中我無法理解IOExceptions。

但是在創建新文件的情況下,通常會先檢查文件是否存在。像這樣:

 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); 
     } 

也許不是你要找的答案。但是,c'est ca.

+0

問題是:另一個進程*可能會在檢查它存在並嘗試創建它之間創建該文件。另一種解決方案可能是在創建失敗後檢查文件是否存在。 –

+0

是的。好決定。 –

0

這不是100%萬無一失(還有其他的原因,一個IOException),但你至少可以排除所有派生的異常類型:

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 
} 

或等價的:

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

至於鏈接的問題,我只是檢查是否存在,提示用戶覆蓋,然後使用OpenOrCreate覆蓋它是否存在。我認爲即使存在覆蓋在錯誤時刻創建的文件的理論風險,大多數應用程序都以這種方式工作。

5

您可以將此條件放入IOException的catch語句中:if(ex.Message.Contains("already exists")) { ... }。這是一種黑客攻擊,但它適用於存在文件的所有情況,即使是臨時文件等。

2

要修改@jgauffin,在C#6,您可以使用File.Existswhen條款內,以避免進入catch塊,從而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

當您嘗試創建一個新的文件,並將其已存在IOException將有Hresult = 0x80070050 (-2147024816)

所以,你的代碼看起來是這樣的:

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曾被保護(見我的第三段),所以這隻在.Net4.5以後纔有效,但是知道它現在可用,謝謝。 – GazTheDestroyer