22

在尝试回答这个问题时,我惊讶地发现在该文件已经存在时尝试创建一个新文件不会抛出一个唯一的异常类型,它只会抛出一个通用的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?
}
4

8 回答 8

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

不适用于可能已再次删除的临时文件等。

这是我的异常最佳实践:https ://coderr.io/exception-handling

于 2012-09-12T13:46:38.947 回答
6

编辑:当文件已经存在时使用另一个 Hresult:0x800700B7 (-2147024713)“当该文件已经存在时无法创建文件”。更新了代码示例。


当您尝试创建一个新文件并且它已经存在时,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 || 
        e.HResult == -2147024713)
    {
        // File already exists.
    }
}
于 2017-03-21T12:05:16.873 回答
5

您可以将此条件放在 IOException: 的 catch 语句中if(ex.Message.Contains("already exists")) { ... }。这是一个 hack,但它适用于文件存在的所有情况,甚至是临时文件等。

于 2014-03-28T12:58:07.843 回答
3

要修改 @jgauffin,在 C# 6 中,您可以使用子句的File.Exists内部when来避免进入catch块,从而表现得更像一个实际的专用异常

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"))
{
   //...
}
于 2016-06-23T18:31:55.623 回答
2

它不是 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如果存在则使用覆盖。我认为大多数应用程序都是这样工作的,即使理论上存在覆盖在错误时刻创建的文件的风险。

于 2012-09-12T14:03:08.337 回答
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。

于 2012-09-12T14:02:57.683 回答
0

在 C# 6 及更高版本中:

const int WARN_WIN32_FILE_EXISTS = unchecked((int)0x80070050);

try
{
    ...
}
catch (IOException e) when (e.HResult == WARN_WIN32_FILE_EXISTS)
{
    ...
}

......或者只是when (e.HResult == -2147024816),如果你想要“快速而坚不可摧”。;-)

(FWIW,以 Windows 为中心的错误代码已被 Mono 忠实复制,也适用于 Mac/Linux。)

于 2018-06-26T09:15:01.880 回答
-1

你应该使用

FileMode.Create

代替

FileMode.CreateNew

如果文件已经存在,它将覆盖文件。

于 2012-09-12T13:47:49.073 回答