【问题标题】:How to detect System.IO.IOException cause by existing file?如何检测现有文件引起的 System.IO.IOException?
【发布时间】:2010-11-08 13:19:12
【问题描述】:

我想创建并打开一个文件,但前提是它不存在。我不想使用 File.Exists,因为线程在创建同名文件后通过 switch 进行。

我如何检查异常 System.IO.IOException 是否是由文件存在引起的?我不想解析错误消息(即使它可以像 .indexOf("exist") 一样简单)

我该怎么做?

【问题讨论】:

  • 文件是信号量,为什么会有这么多争用?
  • DevelopingChris:不,我只是不想意外覆盖它,因为我的 randomId 生成器(使用随机类)可能会由于多核和同步而生成相同的 id
  • 另见stackoverflow.com/questions/425956/…。接受的答案有一个非常有用的链接。

标签: c# asp.net exception-handling ioexception


【解决方案1】:

您应该避免根据 Exception.Message 属性的内容做出逻辑决策。这被定义为人类可读的消息,而不是程序可以读取的东西。此类消息如有更改,恕不另行通知。

人类可读的消息经常会发生变化,以使它们对人类更具可读性。这不会让你的程序更快乐。


您可能会说,依赖于人类可读消息的程序逻辑问题是我的一个小烦恼——我不会告诉你多久,因为那会让我觉得自己老了。这让我从本应显而易见的事情上分心了。

当文件不存在时,请检查您是否收到System.IO.FileNotFoundException。尝试捕获它而不是 IOException。

【讨论】:

  • 这正是问题所在。我不知道如何检查。我想我可以使用 .exist 但感觉很草率。
  • 你错过了我的意思。永远不要检查 Message 属性。
  • 虽然我同意这种观点,但我可以想到例外(没有双关语)。
  • 真的吗?什么时候?也许如果它是您的 Message 属性。否则,你犯的错误很多,只是不频繁,但一直很难找到和修复。我似乎记得在从 .NET 1.1 到 .NET 2.0 的过渡过程中出现了一些损坏的代码——微软已经修复了标点符号,结果人们的代码就损坏了。当然,应该允许微软更正标点符号。这完全不考虑本地化......
  • "你错过了我的意思。永远不要检查 Message 属性"
【解决方案2】:

如果文件已经存在,我不确定他是否想打开它。

我认为他实际上是在 FileMode.CreateNew 之后,如果文件已经存在,这将抛出 IOException,否则将创建并打开它。

【讨论】:

  • 但他担心异常的其他原因 - 例如“权限被拒绝”等。问题的关键在于区分异常的不同可能原因。
  • FileStream 构造函数的文档非常强烈地暗示,在这种模式下,IOException 只会在文件已经存在的情况下被抛出,否则你会得到一个更派生的(和更具体的例外) .所以你是对的,异常处理程序必须检查实际的异常类型是(或不是)IOException
【解决方案3】:

您总是可以从异常捕获块中检查 File.Exists()...。由于线程问题,您不想在之前检查 - 所以在您已经知道有问题之后再检查。

假设您没有突然从另一个线程中删除文件,这将是一种简单而明显的方法。

不要忘记 File.Exists 本身可能会导致异常,所以一定要再次捕获它。

【讨论】:

  • 那里没有竞争条件吗?
  • 不应该有他描述的情况,但这就是我在第二段中暗示的。不过,这可能是解决他的问题的简单方法
  • 还可能需要考虑他期望文件存在的时间百分比
  • 能不能在异常中捕获异常?
  • @acidzombie24 绝对!只需嵌套另一个 try/catch 块。就像它是任何其他类型的控制块一样,例如 if 或 for 循环
【解决方案4】:

您最好的选择是在打开文件进行写入时使用 CreateNew 选项。

没有简单可靠的方法来检查磁盘上是否存在文件。您唯一可以检查的是文件曾经并且可能仍然存在于磁盘上,该进程至少具有有限的访问形式。

即使您从您的应用程序中限制对文件的所有访问,您也无法可靠地阻止其他应用程序创建/删除该文件。即使有足够的文件系统级锁定,用户也可以做一些邪恶的事情,例如从计算机中取出 USB 密钥。

解决此类问题的最佳方法是使用诸如 CreateNew 之类的开放选项。这将允许操作仅在尝试创建时文件不存在时才能成功。您可以此时捕获异常并尝试推断它是来自文件现有还是其他一些无效访问异常。

像 File.Exist 这样的方法会给您的代码库带来虚假的安全感,应该在签入时仔细审查。

【讨论】:

    【解决方案5】:

    您可以使用 File.Open 并使用FileMode.OpenOrCreate 调用它。

    根据评论:好的,FileMode.CreateNew 怎么样?然后,如果已经有一个,你会得到一个 IOException,否则,创建一个新的。

    【讨论】:

    • 哦,我明白了,你的意思是他不想打开它,如果它已经在那里?
    • 他说他想“创建并打开一个文件,但前提是它不存在”。这正是 CreateNew 所做的。我给了 +1 以补偿不公平的 -1。
    • @Steven : -1 并不公平...... JP 之后编辑了他的帖子以添加 CreateNew,但最初他只提到了 OpenOrCreate ;)
    猜你喜欢
    • 2020-09-27
    • 2010-09-21
    • 2016-06-21
    • 1970-01-01
    • 1970-01-01
    • 2016-07-24
    • 1970-01-01
    • 2017-12-22
    • 1970-01-01
    相关资源
    最近更新 更多