在C#中检查目录是否可访问?

14

可能是重复问题:
.NET - 不使用异常处理检查目录是否可访问

我正在使用Visual Studio 2010,.NET 3.5和C#制作一个小型文件浏览器,并且我有这个函数来检查目录是否可访问:

RealPath=@"c:\System Volume Information";
public bool IsAccessible()
{
    //get directory info
    DirectoryInfo realpath = new DirectoryInfo(RealPath);
    try
    {
        //if GetDirectories works then is accessible
        realpath.GetDirectories();                
        return true;
    }
    catch (Exception)
    {
        //if exception is not accesible
        return false;
    }
}

但是我认为在处理大目录时,尝试获取所有子目录来检查目录是否可访问可能会很慢。我正在使用这个函数来防止在没有光盘的情况下探索受保护的文件夹或 CD/DVD 驱动器时出现错误("设备未准备好"错误)。

有没有更好的方法(更快)来检查应用程序是否可以访问目录(最好在.NET 3.5中)?


1
这个代码对于“可访问”的 Directory.Exists ( Path.Combine( RealPath + "." ) ) 有效吗? - kenny
你正在违反Windows资源管理器的工作方式。为什么不显示一个无法访问的文件夹?如果用户看不到它,他就不会知道自己有光驱。 - Amiram Korach
1
https://dev59.com/dXVC5IYBdhLWcg3w-WSs - Anirudha
用户不知道目录是否可访问,如果用户双击“不可访问”的目录,C#会返回一个错误。 - user962284
2个回答

15
根据MSDN,如果您没有读取目录的权限,则Directory.Exists应返回false。但是,您可以使用Directory.GetAccessControl来实现此功能。例如:
public static bool CanRead(string path)
{
    try
    {
        var readAllow = false;
        var readDeny = false;
        var accessControlList = Directory.GetAccessControl(path);
        if(accessControlList == null)
            return false;

        //get the access rules that pertain to a valid SID/NTAccount.
        var accessRules = accessControlList.GetAccessRules(true, true, typeof(System.Security.Principal.SecurityIdentifier));
        if(accessRules ==null)
           return false;

        //we want to go over these rules to ensure a valid SID has access
        foreach (FileSystemAccessRule rule in accessRules)
        {
            if ((FileSystemRights.Read & rule.FileSystemRights) != FileSystemRights.Read) continue;

            if (rule.AccessControlType == AccessControlType.Allow)
                readAllow = true;
            else if (rule.AccessControlType == AccessControlType.Deny)
                readDeny = true;
        }

        return readAllow && !readDeny;
    }
    catch(UnauthorizedAccessException ex)
    {
        return false;
    }
}

更新

如评论中所述,如果外部域中存在有效的SID访问权限,则此方法可能返回不正确的值。为了检查当前用户是否有访问权限,您需要使用以下方式:

foreach...

if (WindowsIdentity.GetCurrent().User.Value.equals(rule.IdentityReference.Value))

这将确认当前用户的SID是否与访问规则身份引用匹配,但也可能会抛出SecurityException异常。

1
不错。accessRules是一个集合,而且永远不会为空,所以这个检查是多余的。最好检查集合是否为空。 - Chris Paton
1
当我尝试使用这个函数时,出现了以下错误:System.UnauthorizedAccessException was unhandled HResult=-2147024891 Message=Attempted to perform an unauthorized operation. - toddmo
1
我尝试读取另一个用户的桌面文件夹C:\users\another user\desktop结果是真的。我尝试从我的计算机进入同一个文件夹 - 但我无法进入。 - Guy Cohen
我猜测在foreach中的第一个检查应该继续,如果accessRule至少具有低于FileSystemRights.ReadFileSystemRights.ListDirectory。这样,对FileSystemRights.ListDirectory拥有AccessControlType.DenyaccessRule将被检测到,并导致readDeny = true的结果。 - modeeb
Directory.Exists 和这个解决方案在大多数情况下都可以使用,但并非全部。使用 Directory.GetAccessControl 可以获取所有访问规则,即使对运行程序集的用户不适用。 - modeeb
显示剩余4条评论

0

我认为你正在寻找GetAccessControl方法,System.IO.File.GetAccessControl方法返回一个FileSecurity对象,该对象封装了文件的访问控制。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接