IOException与检查File.Exists?

时间:2012-08-20 20:21:15

标签: c# wpf performance file-io exception-handling

(我搜索了类似的主题,找不到解决此特定问题的任何内容,但有几个类似的问题,例如herehere。)

我正在评估我们的应用程序的性能,我注意到我们正在获得一些IOExceptions“找不到资源”。我不确定它发生了多少次(很大程度上取决于用户如何使用该应用程序),但它至少有十几个左右。

我假设一般的异常性能都很高,文件I / O调用就像File.Exists()一样。我知道在尝试加载文件之前检查文件是否存在总是很好的做法。我的问题是,如果我检查这个特定文件是否存在,我会看到多少性能提升? (再次,忽略“你应该这样做”,我只是想了解一下表现)。

选项1:

try
{
    return (ResourceDictionary) Application.LoadComponent(uri);
}
catch (Exception)
{
    //If it's not there, don't do anything
}

这不会产生额外的IO调用,但有时会抛出并吞噬异常。

选项2

if(File.Exists(uri))
{
    return (ResourceDictionary) Application.LoadComponent(uri);
}

3 个答案:

答案 0 :(得分:6)

通常,如果文件应该存在(即:它是应用程序部署的一部分),那么我将使用异常检查,而不是其他任何内容。这是因为,在这种情况下,例外确实是一种特殊和意想不到的情况。

如果文件是用户输入的内容,则检查存在是否具有潜在意义。但是,这仍然不能消除异常处理的需要,因为在您检查的时间和打开/使用它之间删除文件 。因此,您仍然需要异常处理 - 在这种情况下,可能仍然只想使用您的第一个选项代码,但要确保异常处理足够干净以便始终提供行为,甚至如果文件不存在。

答案 1 :(得分:1)

我看不出你们两个选项之间存在巨大的性能差异。大多数工作是定位和读取文件,所以在这两种情况下你都必须这样做。如果您不希望用户在应用程序运行时添加/删除此文件,则可能有用的是缓存结果。所以你可能会做类似

的事情
private static Dictionary<Uri, ResourceDictionary> _uriToResources =
  new Dictionary<Uri, ResourceDictionary>();
public static ResourceDictionary GetResourceDictionary(Uri uri)
{
  ResourceDictionary resources;
  if (_uriToResources.TryGetValue(uri, out resources))
  {
    return resources;
  }

  try
  {
     resources = (ResourceDictionary)Application.LoadComponent(uri);
  }
  catch
  {
     // could prompt/alert the user here.
     resources = null; // or an appropriate default.
  }

  _uriToResources[uri] = resources;
  return resources;
}

这可以防止您重复尝试加载不存在的资源。这里我返回一个null对象,但最好使用一些默认值作为后备。

答案 2 :(得分:1)

File.Exists也在内部抛出异常。因此性能将非常相似。

以下是File.cs中的代码,其中包含File.Exists调用的辅助方法。

 [SecurityCritical]
    private static bool InternalExistsHelper(string path, bool checkHost)
    {
      try
      {
        if (path == null || path.Length == 0)
          return false;
        path = Path.GetFullPathInternal(path);
        if (path.Length > 0 && Path.IsDirectorySeparator(path[path.Length - 1]))
          return false;
        FileIOPermission.QuickDemand(FileIOPermissionAccess.Read, path, false, false);
        return File.InternalExists(path);
      }
      catch (ArgumentException ex)
      {
      }
      catch (NotSupportedException ex)
      {
      }
      catch (SecurityException ex)
      {
      }
      catch (IOException ex)
      {
      }
      catch (UnauthorizedAccessException ex)
      {
      }
      return false;
    }