C# UnauthorizedAccessException 无法解决 Directory.GetFiles 失败
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1393178/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
UnauthorizedAccessException cannot resolve Directory.GetFiles failure
提问by Ric
Directory.GetFiles methodfails on the first encounter with a folder it has no access rights to.
Directory.GetFiles 方法在第一次遇到它没有访问权限的文件夹时失败。
The method throws an UnauthorizedAccessException (which can be caught) but by the time this is done, the method has already failed/terminated.
该方法抛出一个 UnauthorizedAccessException(可以被捕获),但是当它完成时,该方法已经失败/终止。
The code I am using is listed below:
我正在使用的代码如下所示:
try
{
// looks in stated directory and returns the path of all files found
getFiles = Directory.GetFiles(
@directoryToSearch,
filetype,
SearchOption.AllDirectories);
}
catch (UnauthorizedAccessException)
{
}
As far as I am aware, there is no way to check beforehand whether a certain folder has access rights defined.
据我所知,没有办法事先检查某个文件夹是否定义了访问权限。
In my example, I'm searching on a disk across a network and when I come across a root access only folder, my program fails.
在我的示例中,我正在通过网络搜索磁盘,当我遇到一个只能访问根目录的文件夹时,我的程序失败了。
采纳答案by Fredrik M?rk
In order to gain control on the level that you want, you should probably probe one directory at a time, instead of a whole tree. The following method populates the given IList<string>
with all files found in the directory tree, except those where the user doesn't have access:
为了获得所需级别的控制权,您可能应该一次探测一个目录,而不是一整棵树。以下方法IList<string>
使用目录树中找到的所有文件填充给定文件,用户无权访问的文件除外:
// using System.Linq
private static void AddFiles(string path, IList<string> files)
{
try
{
Directory.GetFiles(path)
.ToList()
.ForEach(s => files.Add(s));
Directory.GetDirectories(path)
.ToList()
.ForEach(s => AddFiles(s, files));
}
catch (UnauthorizedAccessException ex)
{
// ok, so we are not allowed to dig into that directory. Move on.
}
}
回答by Ian Mercer
In .NET 4 this becomes a lot easier, see http://msdn.microsoft.com/en-us/library/dd997370.aspx
在 .NET 4 中,这变得容易多了,请参阅http://msdn.microsoft.com/en-us/library/dd997370.aspx
回答by Malcolm
.Net 4's Directory.EnumerateFiles does work, but you've got to be careful how you evaluate the enumerable and do that part inside the try-catch block. The biggest issue is making sure you don't stop processing at the first exception (which I think answer https://stackoverflow.com/a/1393219/89584above has this problem, please correct me if I'm wrong there).
.Net 4 的 Directory.EnumerateFiles 确实有效,但您必须小心如何评估可枚举并在 try-catch 块内执行该部分。最大的问题是确保您不会在第一个异常时停止处理(我认为上面的回答https://stackoverflow.com/a/1393219/89584有这个问题,如果我错了,请纠正我)。
The following works and gives you an Enumerable so you don't have to evaluate the entire file tree if you're looking for the first match, etc.
以下工作并为您提供一个 Enumerable ,因此如果您正在寻找第一个匹配项等,则不必评估整个文件树。
private IEnumerable<String> FindAccessableFiles(string path, string file_pattern, bool recurse)
{
IEnumerable<String> emptyList = new string[0];
if (File.Exists(path))
return new string[] { path };
if (!Directory.Exists(path))
return emptyList;
var top_directory = new DirectoryInfo(path);
// Enumerate the files just in the top directory.
var files = top_directory.EnumerateFiles(file_pattern);
var filesLength = files.Count();
var filesList = Enumerable
.Range(0, filesLength)
.Select(i =>
{
string filename = null;
try
{
var file = files.ElementAt(i);
filename = file.FullName;
}
catch (UnauthorizedAccessException)
{
}
catch (InvalidOperationException)
{
// ran out of entries
}
return filename;
})
.Where(i => null != i);
if (!recurse)
return filesList;
var dirs = top_directory.EnumerateDirectories("*");
var dirsLength = dirs.Count();
var dirsList = Enumerable
.Range(0, dirsLength)
.SelectMany(i =>
{
string dirname = null;
try
{
var dir = dirs.ElementAt(i);
dirname = dir.FullName;
return FindAccessableFiles(dirname, file_pattern, required_extension, recurse);
}
catch (UnauthorizedAccessException)
{
}
catch (InvalidOperationException)
{
// ran out of entries
}
return emptyList;
})
return Enumerable.Concat(filesList, dirsList);
}
improvements to the above welcome.
以上欢迎改进。
回答by matrix
This is an enhancement to Malcolm's answer (http://stackoverflow.com/a/9831340/226181). This scans all logical drives for a file match pattern and ignores the directories that are not accessible.
这是对 Malcolm 答案的增强 (http://stackoverflow.com/a/9831340/226181)。这会扫描所有逻辑驱动器的文件匹配模式并忽略不可访问的目录。
static List<string> SearchFiles(string pattern)
{
var result = new List<string>();
foreach (string drive in Directory.GetLogicalDrives())
{
Console.WriteLine("searching " + drive);
var files = FindAccessableFiles(drive, pattern, true);
Console.WriteLine(files.Count().ToString() + " files found.");
result.AddRange(files);
}
return result;
}
private static IEnumerable<String> FindAccessableFiles(string path, string file_pattern, bool recurse)
{
Console.WriteLine(path);
var list = new List<string>();
var required_extension = "mp4";
if (File.Exists(path))
{
yield return path;
yield break;
}
if (!Directory.Exists(path))
{
yield break;
}
if (null == file_pattern)
file_pattern = "*." + required_extension;
var top_directory = new DirectoryInfo(path);
// Enumerate the files just in the top directory.
IEnumerator<FileInfo> files;
try
{
files = top_directory.EnumerateFiles(file_pattern).GetEnumerator();
}
catch (Exception ex)
{
files = null;
}
while (true)
{
FileInfo file = null;
try
{
if (files != null && files.MoveNext())
file = files.Current;
else
break;
}
catch (UnauthorizedAccessException)
{
continue;
}
catch (PathTooLongException)
{
continue;
}
yield return file.FullName;
}
if (!recurse)
yield break;
IEnumerator<DirectoryInfo> dirs;
try
{
dirs = top_directory.EnumerateDirectories("*").GetEnumerator();
}
catch (Exception ex)
{
dirs = null;
}
while (true)
{
DirectoryInfo dir = null;
try
{
if (dirs != null && dirs.MoveNext())
dir = dirs.Current;
else
break;
}
catch (UnauthorizedAccessException)
{
continue;
}
catch (PathTooLongException)
{
continue;
}
foreach (var subpath in FindAccessableFiles(dir.FullName, file_pattern, recurse))
yield return subpath;
}
}
回答by schnaidar
I know this thread is old, but in case someone stumbles upon this and needs an answer, i got a recursive solution here:
我知道这个线程很旧,但如果有人偶然发现并需要答案,我在这里得到了一个递归解决方案:
public static List<string> GetAllAccessibleFiles(string rootPath, List<string> alreadyFound = null)
{
if (alreadyFound == null)
alreadyFound = new List<string>();
DirectoryInfo di = new DirectoryInfo(rootPath);
var dirs = di.EnumerateDirectories();
foreach (DirectoryInfo dir in dirs)
{
if (!((dir.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden))
{
alreadyFound = GetAllAccessibleFiles(dir.FullName, alreadyFound);
}
}
var files = Directory.GetFiles(rootPath);
foreach (string s in files)
{
alreadyFound.Add(s);
}
return alreadyFound;
}
It returns an List<string>
containing the full path to all files that are in accessible directories below the given root-directory.
Call it like this:
它返回一个List<string>
包含所有文件的完整路径,这些文件位于给定根目录下的可访问目录中。像这样调用它:
var files = GetAllAccessibleFiles(@"C:\myDirectory");
So one result could be like this:
所以一个结果可能是这样的:
C:\myDirectory\a\a.txt
C:\myDirectory\a\b.mp3
C:\myDirectory\b\a\a\foo.txt
C:\myDirectory\b\b\b\hello.exe
C:\myDirectory\b\c\bar.jpg
C:\myDirectory\and\so\on.bar
C:\myDirectory\a_file_in_root.bmp
Hope it helps someone!
希望它可以帮助某人!
回答by Kosmos
public string[] GetFilesFrom(string dir, string search_pattern, bool recursive)
{
List<string> files = new List<string>();
string[] temp_files = new string[0];
try { temp_files = Directory.GetFiles(dir, search_pattern, SearchOption.TopDirectoryOnly); }
catch { }
files.AddRange(temp_files);
if (recursive)
{
string[] temp_dirs = new string[0];
try { temp_dirs = Directory.GetDirectories(dir, search_pattern, SearchOption.TopDirectoryOnly); }
catch { }
for (int i = 0; i < temp_dirs.Length; i++)
files.AddRange(GetFilesFrom(temp_dirs[i], search_pattern, recursive));
}
return files.ToArray();
}
This is my solution for this problem. Simple and fail safe.
这是我对这个问题的解决方案。简单且故障安全。
回答by Bohdan
The simplest version:
最简单的版本:
IEnumerable<String> GetAllFiles(string path, string searchPattern)
{
return System.IO.Directory.EnumerateFiles(path, searchPattern).Union(
System.IO.Directory.EnumerateDirectories(path).SelectMany(d =>
{
try
{
return GetAllFiles(d, searchPattern);
}
catch (UnauthorizedAccessException e)
{
return Enumerable.Empty<String>();
}
}));
}