我正在尝试显示在所选目录中找到的所有文件的列表(以及可选的任何子目录)。我遇到的问题是,当GetFiles()方法遇到无法访问的文件夹时,它会抛出异常并且进程停止。
如何忽略此异常(并忽略受保护的文件夹/文件)并继续将可访问文件添加到列表中?
try
{
if (cbSubFolders.Checked == false)
{
string[] files = Directory.GetFiles(folderBrowserDialog1.SelectedPath);
foreach (string fileName in files)
ProcessFile(fileName);
}
else
{
string[] files = Directory.GetFiles(folderBrowserDialog1.SelectedPath, "*.*", SearchOption.AllDirectories);
foreach (string fileName in files)
ProcessFile(fileName);
}
lblNumberOfFilesDisplay.Enabled = true;
}
catch (UnauthorizedAccessException) { }
finally {}
答案 0 :(得分:47)
你必须手动进行递归;不要使用AllDirectories - 一次查看一个文件夹,然后尝试从sub-dirs获取文件。未经测试,但如下所示(注意使用委托而不是构建数组):
using System;
using System.IO;
static class Program
{
static void Main()
{
string path = ""; // TODO
ApplyAllFiles(path, ProcessFile);
}
static void ProcessFile(string path) {/* ... */}
static void ApplyAllFiles(string folder, Action<string> fileAction)
{
foreach (string file in Directory.GetFiles(folder))
{
fileAction(file);
}
foreach (string subDir in Directory.GetDirectories(folder))
{
try
{
ApplyAllFiles(subDir, fileAction);
}
catch
{
// swallow, log, whatever
}
}
}
}
答案 1 :(得分:12)
这个简单的功能运作良好,符合问题要求。
private List<string> GetFiles(string path, string pattern)
{
var files = new List<string>();
try
{
files.AddRange(Directory.GetFiles(path, pattern, SearchOption.TopDirectoryOnly));
foreach (var directory in Directory.GetDirectories(path))
files.AddRange(GetFiles(directory, pattern));
}
catch (UnauthorizedAccessException) { }
return files;
}
答案 2 :(得分:6)
答案 3 :(得分:5)
一种简单的方法是使用List for files和Queue for directories。 它节省了记忆。 如果使用递归程序执行相同的任务,则可能抛出OutOfMemory异常。 输出:List中添加的文件根据从上到下(广度优先)目录树进行组织。
public static List<string> GetAllFilesFromFolder(string root, bool searchSubfolders) {
Queue<string> folders = new Queue<string>();
List<string> files = new List<string>();
folders.Enqueue(root);
while (folders.Count != 0) {
string currentFolder = folders.Dequeue();
try {
string[] filesInCurrent = System.IO.Directory.GetFiles(currentFolder, "*.*", System.IO.SearchOption.TopDirectoryOnly);
files.AddRange(filesInCurrent);
}
catch {
// Do Nothing
}
try {
if (searchSubfolders) {
string[] foldersInCurrent = System.IO.Directory.GetDirectories(currentFolder, "*.*", System.IO.SearchOption.TopDirectoryOnly);
foreach (string _current in foldersInCurrent) {
folders.Enqueue(_current);
}
}
}
catch {
// Do Nothing
}
}
return files;
}
答案 4 :(得分:4)
从.NET Standard 2.1开始,您现在可以执行以下操作:
var filePaths = Directory.EnumerateFiles(@"C:\my\files", "*.xml", new EnumerationOptions
{
IgnoreInaccessible = true,
RecurseSubdirectories = true
});
根据MSDN docs关于 IgnoreInaccessible :
获取或设置一个值,该值指示拒绝访问时是否跳过文件或目录(例如,UnauthorizedAccessException或SecurityException)。默认值为true。
默认值实际上是真实的,但我将其保留在此处只是为了显示该属性。
DirectoryInfo
也可以使用相同的重载。
答案 5 :(得分:3)
我知道这个问题有些陈旧,但今天我遇到了同样的问题,我发现以下文章详细解释了“文件夹递归”解决方案。
文章承认GetDirectories()
方法的缺陷......:
不幸的是,[[strong> 使用GetDirectories()方法 ]存在问题。其中的关键是一些 您尝试读取的文件夹可以配置为 当前用户可能无法访问它们。而不是忽略文件夹 你有限制访问权限,该方法抛出一个 UnauthorizedAccessException。但是,我们可以绕过这个问题 通过创建我们自己的递归文件夹搜索代码。
...然后详细介绍解决方案:
答案 6 :(得分:2)
这应该回答这个问题。我忽略了通过子目录的问题,我假设你已经弄明白了。
当然,你不需要有一个单独的方法,但你可能会发现它也是一个有用的地方,也可以验证路径是否有效,并处理调用GetFiles()时可能遇到的其他异常
希望这有帮助。
private string[] GetFiles(string path)
{
string[] files = null;
try
{
files = Directory.GetFiles(path);
}
catch (UnauthorizedAccessException)
{
// might be nice to log this, or something ...
}
return files;
}
private void Processor(string path, bool recursive)
{
// leaving the recursive directory navigation out.
string[] files = this.GetFiles(path);
if (null != files)
{
foreach (string file in files)
{
this.Process(file);
}
}
else
{
// again, might want to do something when you can't access the path?
}
}
答案 7 :(得分:1)
请参阅https://stackoverflow.com/a/10728792/89584以获取处理UnauthorisedAccessException问题的解决方案。
如果对GetFiles()或GetDirectories()的任何调用都在具有多种权限的文件夹上,则上述所有解决方案都将丢失文件和/或目录。
答案 8 :(得分:0)
您甚至可以更改已生成的List
个文件以跳过FileSystemInfo
版本中的目录!
(注意null
值!)
public static IEnumerable<KeyValuePair<string, string[]>> GetFileSystemInfosRecursive(string dir, bool depth_first)
{
foreach (var item in GetFileSystemObjectsRecursive(new DirectoryInfo(dir), depth_first))
{
string[] result;
var children = item.Value;
if (children != null)
{
result = new string[children.Count];
for (int i = 0; i < result.Length; i++)
{ result[i] = children[i].Name; }
}
else { result = null; }
string fullname;
try { fullname = item.Key.FullName; }
catch (IOException) { fullname = null; }
catch (UnauthorizedAccessException) { fullname = null; }
yield return new KeyValuePair<string, string[]>(fullname, result);
}
}
public static IEnumerable<KeyValuePair<DirectoryInfo, List<FileSystemInfo>>> GetFileSystemInfosRecursive(DirectoryInfo dir, bool depth_first)
{
var stack = depth_first ? new Stack<DirectoryInfo>() : null;
var queue = depth_first ? null : new Queue<DirectoryInfo>();
if (depth_first) { stack.Push(dir); }
else { queue.Enqueue(dir); }
for (var list = new List<FileSystemInfo>(); (depth_first ? stack.Count : queue.Count) > 0; list.Clear())
{
dir = depth_first ? stack.Pop() : queue.Dequeue();
FileSystemInfo[] children;
try { children = dir.GetFileSystemInfos(); }
catch (UnauthorizedAccessException) { children = null; }
catch (IOException) { children = null; }
if (children != null) { list.AddRange(children); }
yield return new KeyValuePair<DirectoryInfo, List<FileSystemInfo>>(dir, children != null ? list : null);
if (depth_first) { list.Reverse(); }
foreach (var child in list)
{
var asdir = child as DirectoryInfo;
if (asdir != null)
{
if (depth_first) { stack.Push(asdir); }
else { queue.Enqueue(asdir); }
}
}
}
}
答案 9 :(得分:0)
我更喜欢使用c#框架函数,但是我需要的函数将包含在.net Framework 5.0中,所以我必须编写它。
// search file in every subdirectory ignoring access errors
static List<string> list_files(string path)
{
List<string> files = new List<string>();
// add the files in the current directory
try
{
string[] entries = Directory.GetFiles(path);
foreach (string entry in entries)
files.Add(System.IO.Path.Combine(path,entry));
}
catch
{
// an exception in directory.getfiles is not recoverable: the directory is not accessible
}
// follow the subdirectories
try
{
string[] entries = Directory.GetDirectories(path);
foreach (string entry in entries)
{
string current_path = System.IO.Path.Combine(path, entry);
List<string> files_in_subdir = list_files(current_path);
foreach (string current_file in files_in_subdir)
files.Add(current_file);
}
}
catch
{
// an exception in directory.getdirectories is not recoverable: the directory is not accessible
}
return files;
}