2012-09-12 39 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