【问题标题】:The morass of Exceptions related to opening a FileStream与打开 FileStream 相关的异常泥潭
【发布时间】:2012-02-21 00:33:37
【问题描述】:

好的,所以我已经在很多地方搜索过这个问题的答案,但是如果我错过了一些明显的东西,我愿意接受任何链接。

我有兴趣在用户尝试打开特定文件时向他们提供合理的错误消息,但无论出于何种原因程序无法访问该文件。我想区分以下几种情况:

  • 该文件已被另一个进程锁定,因此该进程无法对其进行写入。
  • 用户没有适当的访问权限来写入文件(例如,他们的用户权限,如 Windows 资源管理器中文件的“属性”屏幕所示,不授予用户写入权限)
  • 该文件需要“提升”权限才能访问该文件。

我正在使用 FileStream 对象。我看过msdn documentation for instantiating a FileStream,我完全不清楚哪个异常对上述内容做了什么,以及如何区分它们。我承认我在 Windows 编程方面的经验是有限的,所以我可能遗漏了一些明显的东西。如果是这样,我很抱歉。

【问题讨论】:

  • 您要检查的最后两个案例之间有区别吗?我可以想象(虽然还没有证明)他们都会抛出一个SecurityException,而第一个案例会抛出一个IOException
  • @M.Babcock:在某些方面,最后两种情况并没有太大的不同。但是,用户必须(通常)做非常不同的事情才能访问文件。对于第二种情况,他们可能需要请求另一个用户授予他们权限。对于第三种情况,他们需要“以管理员身份运行”或者可能将文件移出“程序文件”目录(尽管我不知道它为什么会在那里)。我想帮助用户了解他们需要做什么才能访问该文件。
  • 再一次,我可能在我之前的评论中表现出我对 Windows 操作系统的无知 - 如果我的解释不正确,我愿意更正。
  • 有道理。听起来您正在寻找的东西应该可以通过一系列测试和检查抛出的异常来发现。只是预感,您也许可以使用SecurityExceptionHResult 属性来确定根本原因。

标签: c# exception-handling filestream


【解决方案1】:

你可以这样做:

1) 您可以在尝试访问您的文件之前测试您是否有权访问该文件。从this SO thread 开始,如果用户拥有Write 权限(即右键单击文件-> 属性-> 安全性),这里有一个方法应该返回true。这涵盖了您的观点 (2) 对于不适当的访问权限(请注意,可能有比下面的代码更强大/防错的方法来获取此信息):

public static bool HasWritePermissionOnFile(string path)
{
    bool writeAllow = false;
    bool writeDeny = false;

    FileSecurity accessControlList = File.GetAccessControl(path);
    if (accessControlList == null)
    {
        return false;
    }

    var accessRules = accessControlList.GetAccessRules(true, true, typeof(SecurityIdentifier));
    if (accessRules == null)
    {
        return false;
    }

    foreach (FileSystemAccessRule rule in accessRules)
    {
        if ((FileSystemRights.Write & rule.FileSystemRights) != FileSystemRights.Write)
        {
            continue;
        }

        if (rule.AccessControlType == AccessControlType.Allow)
        {
            writeAllow = true;
        }
        else if (rule.AccessControlType == AccessControlType.Deny)
        {
            writeDeny = true;
        }
    }

    return writeAllow && !writeDeny;
}

2) 请尝试实例化您的FileStream,并捕获异常:

try
{
    string file = "...";
    bool hasWritePermission = HasWritePermissionOnFile(file);
    using (FileStream fs = new FileStream(file, FileMode.Open))
    {
    }
}
catch (UnauthorizedAccessException ex)
{
    // Insert some logic here
}
catch (FileNotFoundException ex)
{
    // Insert some logic here
}
catch (IOException ex)
{
    // Insert some logic here
}

在您的情况 (3) 中(文件需要提升),UnauthorizedAccessException 被抛出。

在您的情况 (1) 中(文件被另一个进程锁定),IOException 被抛出。然后,您可以检查异常的 HRESULT 以了解更多详细信息:

catch (IOException ex)
{
    // Gets the HRESULT
    int hresult = Marshal.GetHRForException(ex);

    // See http://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx
    // for system error code
    switch (hresult & 0x0000FFFF)
    {
        case 32:    //ERROR_SHARING_VIOLATION
            Console.WriteLine("File is in use by another process");
            break;
    }
}

现在您应该能够区分您的 3 个用例了。

【讨论】:

  • 嗯。这是有道理的——我将对此进行测试。尽管我认为我不能完全信任您在此处指定的解决方案 1,因为可能存在竞争条件。也就是说,a)我的进程检查它是否可以访问文件,b)其他进程打开文件(或更改权限等),c)我的进程尝试打开文件并失败/变得暴躁/等。
  • 实际上,如果用户在HasWritePermissionOnFile 检查和new FileStream 调用之间失去了权限,则可能仅针对情况(2)(未分配的访问权限)存在竞争条件。如果发生,会抛出UnauthorizedAccessException 异常,因此您仍然可以知道“存在访问问题”。然后,您可以在 catch (UnauthorizedAccessException) 块内调用 HasWritePermissionOnFile 以确保在因海拔问题引发异常时发生异常。
  • 哈,感觉这只会将竞争条件移动到 UnauthorizedAccessException 的 catch 块中。虽然我不确定是否可以避免这种情况。或者有吗?它肯定在正常条件下工作。谢谢!
  • 出于好奇,什么会导致在尝试实例化 FileStream 时抛出 SecurityException?
  • @skybluecodeflier 是的。好吧,如果某个进程不断更改文件的安全属性,则很难准确知道是什么原因导致UnauthorizedAccessException 异常被抛出;)实际上它对我来说看起来不是一个常见的用例。
猜你喜欢
  • 1970-01-01
  • 2019-01-28
  • 2016-08-30
  • 2023-03-11
  • 1970-01-01
  • 1970-01-01
  • 2011-06-25
  • 1970-01-01
  • 2013-03-15
相关资源
最近更新 更多