The issues is permissions, not code per-say. You could handle it as follows where on error continue with a recursive process
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace **Your namespace**
{
public class DirectoryOperations
{
public static List<string> GetAllAccessibleDirectories(string path, string searchPattern)
{
var dirPathList = new List<string>();
try
{
var childDirPathList = Directory.GetDirectories(path, searchPattern, SearchOption.TopDirectoryOnly).ToList();
if (childDirPathList.Count <= 0)
{
return null;
}
foreach (var childDirPath in childDirPathList)
{
dirPathList.Add(childDirPath);
List<string> grandChildDirPath = GetAllAccessibleDirectories(childDirPath, searchPattern);
if (grandChildDirPath != null && grandChildDirPath.Count > 0)
{
dirPathList.AddRange(grandChildDirPath.ToArray());
}
}
return dirPathList;
}
catch
{
return null;
}
}
}
}
Usage
DirectoryOperations.GetAllAccessibleDirectories(@"C:\", "*");
Or be specific with the exception type of UnauthorizedAccessException
public static IEnumerable<string> GetAllFiles(string path, string searchPattern)
{
return Directory.EnumerateFiles(path, searchPattern).Union(
Directory.EnumerateDirectories(path).SelectMany(d =>
{
try
{
return GetAllFiles(d, searchPattern);
}
catch (UnauthorizedAccessException e)
{
return Enumerable.Empty<String>();
}
}));
}
Or even better yet an advance solution the following
- Is asynchronous which means the UI remains responsive.
- Provides events to track the operations which is especially useful for large directory structures.
- Checks for specific errors like UnauthorizedAccessException
- Attempts to figure out which folders to skip reading
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using System.Xml.Linq; using System.IO; using System.Threading; namespace FileHelpers { public class Operations { public delegate void OnException(Exception exception); public static event OnException OnExceptionEvent; public delegate void OnUnauthorizedAccessException(string message); public static event OnUnauthorizedAccessException UnauthorizedAccessExceptionEvent; public delegate void OnTraverseFolder(string status); public static event OnTraverseFolder OnTraverseEvent; public delegate void OnTraverseExcludeFolder(string sender); public static event OnTraverseExcludeFolder OnTraverseExcludeFolderEvent; public static bool Cancelled = false; public static async Task RecursiveFolders(DirectoryInfo directoryInfo, string[] excludeFileExtensions, CancellationToken ct) { if (!directoryInfo.Exists) { if (OnTraverseEvent != null) OnTraverseEvent("Nothing to process"); return; } if (!excludeFileExtensions.Any(directoryInfo.FullName.Contains)) { await Task.Delay(1); if (OnTraverseEvent != null) OnTraverseEvent(directoryInfo.FullName); } else { if (OnTraverseExcludeFolderEvent != null) OnTraverseExcludeFolderEvent(directoryInfo.FullName); } DirectoryInfo folder = null; try { await Task.Run(async () => { foreach (DirectoryInfo dir in directoryInfo.EnumerateDirectories()) { folder = dir; if ((folder.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden || (folder.Attributes & FileAttributes.System) == FileAttributes.System || (folder.Attributes & FileAttributes.ReparsePoint) == FileAttributes.ReparsePoint) { if (OnTraverseExcludeFolderEvent != null) OnTraverseExcludeFolderEvent($"* {folder.FullName}"); continue; } if (!Cancelled) { await Task.Delay(1); await RecursiveFolders(folder, excludeFileExtensions, ct); } else { return; } if (ct.IsCancellationRequested) { ct.ThrowIfCancellationRequested(); } } }); } catch (Exception ex) { if (ex is OperationCanceledException) { Cancelled = true; } else if (ex is UnauthorizedAccessException) { if (UnauthorizedAccessExceptionEvent != null) UnauthorizedAccessExceptionEvent($"Access denied '{ex.Message}'"); } else { if (OnExceptionEvent != null) OnExceptionEvent(ex); } } } public static void RecursiveFolders(string path, int indentLevel) { try { if ((File.GetAttributes(path) & FileAttributes.ReparsePoint) != FileAttributes.ReparsePoint) { foreach (string folder in Directory.GetDirectories(path)) { Debug.WriteLine($"{new string(' ', indentLevel)}{System.IO.Path.GetFileName(folder)}"); RecursiveFolders(folder, indentLevel + 2); } } } catch (UnauthorizedAccessException unauthorized) { Debug.WriteLine($"{unauthorized.Message}"); } } } }
Edit
The following code can be viewed online or downloaded (if familiar with Git) using the following script. To keep things simple I show progress in a label but you can also use any control you want.
mkdir code
cd code
git init
git remote add -f origin https://github.com/karenpayneoregon/csharp-features
git sparse-checkout init --cone
git sparse-checkout add FileHelpers
git sparse-checkout add FileHelpersFrontEnd
git pull origin master
:clean-up
del .gitattributes
del .gitignore
del .yml
del .editorconfig
del *.md
del *.sln
Backend class project
https://github.com/karenpayneoregon/csharp-features/tree/master/FileHelpers
Frontend form code
Change the path and exclude extensions to match your needs
using System;
using System.IO;
using System.Threading;
using System.Windows.Forms;
using FileHelpers;
namespace FileHelpersFrontEnd
{
public partial class Form1 : Form
{
private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
public Form1()
{
InitializeComponent();
Operations.OnTraverseEvent += OperationsOnOnTraverseEvent;
}
private void OperationsOnOnTraverseEvent(string status)
{
ResultsLabel.InvokeIfRequired(label =>
{
label.Text = status;
label.Refresh();
});
}
private async void RunButton_Click(object sender, EventArgs e)
{
if (_cancellationTokenSource.IsCancellationRequested)
{
_cancellationTokenSource.Dispose();
_cancellationTokenSource = new CancellationTokenSource();
}
var directoryInfo = new DirectoryInfo("C:\\OED\\Dotnetland\\VS2019\\csharp-tips");
try
{
await Operations.RecursiveFolders(
directoryInfo,
new[] { "*.txt" },
_cancellationTokenSource.Token);
if (Operations.Cancelled)
{
MessageBox.Show(@"You cancelled the operation");
}
else
{
MessageBox.Show(@"Done");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void CancelButton_Click(object sender, EventArgs e)
{
_cancellationTokenSource.Cancel();
}
}
}
To prevent cross threading issues use the following extension.