I am trying to display a list of all files found in the selected directory (and optionally any subdirectories). The problem I am having is that when the GetFiles() method comes across a folder that it cannot access, it throws an exception and the process stops.
How do I ignore this exception (and ignore the protected folder/file) and continue adding accessible files to the list?
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 {}
You will have to do the recursion manually; don't use AllDirectories - look one folder at a time, then try getting the files from sub-dirs. Untested, but something like below (note uses a delegate rather than building an array):
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
}
}
}
}
Since .NET Standard 2.1 (.NET Core 3+, .NET 5+), you can now just do:
var filePaths = Directory.EnumerateFiles(#"C:\my\files", "*.xml", new EnumerationOptions
{
IgnoreInaccessible = true,
RecurseSubdirectories = true
});
According to the MSDN docs about IgnoreInaccessible:
Gets or sets a value that indicates whether to skip files or directories when access is denied (for example, UnauthorizedAccessException or SecurityException). The default is true.
Default value is actually true, but I've kept it here just to show the property.
The same overload is available for DirectoryInfo as well.
This simple function works well and meets the questions requirements.
private List<string> GetFiles(string path, string pattern)
{
var files = new List<string>();
var directories = new string[] { };
try
{
files.AddRange(Directory.GetFiles(path, pattern, SearchOption.TopDirectoryOnly));
directories = Directory.GetDirectories(path);
}
catch (UnauthorizedAccessException) { }
foreach (var directory in directories)
try
{
files.AddRange(GetFiles(directory, pattern));
}
catch (UnauthorizedAccessException) { }
return files;
}
A simple way to do this is by using a List for files and a Queue for directories.
It conserves memory.
If you use a recursive program to do the same task, that could throw OutOfMemory exception.
The output: files added in the List, are organised according to the top to bottom (breadth first) directory tree.
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;
}
Steps:
Enqueue the root in the queue
In a loop, Dequeue it, Add the files in that directory to the list, and Add the subfolders to the queue.
Repeat untill the queue is empty.
see https://stackoverflow.com/a/10728792/89584 for a solution that handles the UnauthorisedAccessException problem.
All the solutions above will miss files and/or directories if any calls to GetFiles() or GetDirectories() are on folders with a mix of permissions.
Here's a full-featured, .NET 2.0-compatible implementation.
You can even alter the yielded List of files to skip over directories in the FileSystemInfo version!
(Beware null values!)
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); }
}
}
}
}
This should answer the question. I've ignored the issue of going through subdirectories, I'm assuming you have that figured out.
Of course, you don't need to have a seperate method for this, but you might find it a useful place to also verify the path is valid, and deal with the other exceptions that you could encounter when calling GetFiles().
Hope this helps.
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?
}
}
I prefer using c# framework functions, but the function i need will be included in .net framework 5.0, so i have to write it.
// 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;
}
I am developing a Windows 10 UWP application and anytime I run the below code, I get the following execption:
'UnauthorizedAccessException - Access to path {path name} is denied'.
I have tried the several windows folders (path) :
Pictures,
Videos
Desktop etc.
This is my code:
public async Task GetFiles() // edit added wrapper method for readability
{
var filePicker = new FileOpenPicker();
filePicker.FileTypeFilter.Add("*");
Windows.Storage.StorageFile file = await filePicker.PickSingleFileAsync();
if (file != null)
{
ChosenFiles.ItemsSource = GetFileInfo(file.Path);
}
}
public List<string> GetFileInfo(string path)
{
List<string> files = new List<string>();
string[] allFiles = Directory.GetFiles(path);
foreach (var file in allFiles)
{
FileInfo Info = new FileInfo(file);
files.Add(Info.Name);
}
return files;
}
System.IO.Directory seems to only have direct access to app package and app local storage folders. That means you should rather use StorageFile and StorageFolder classes to extract information you need. For example:
private async void ButtonBase_OnClick(object sender, RoutedEventArgs args)
{
var folderPicker = new FolderPicker();
var folder = await folderPicker.PickSingleFolderAsync();
if (folder != null)
{
ChosenFiles.ItemsSource = await GetFileInfoAsync(folder);
}
}
public async Task<List<string>> GetFileInfoAsync(StorageFolder folder)
{
List<string> files = new List<string>();
var allFiles = await folder.GetFilesAsync();
foreach (var file in allFiles)
{
files.Add(file.Name);
}
return files;
}
Note that if you picked a file, you can't enumerate its neighbors because you don't have access to its parent folder. So for your scenario you should use FolderPicker.
My outlook client has a shared folder "xxxx yyyy". However, the following code, which iterates all the folder and sub folder recursively, doesn't print out the folder. Why the code cannot get the folder?
private static void PrintAllPubFolder(ExchangeService service)
{
var folderView = new FolderView(int.MaxValue);
var findFolderResults = service.FindFolders(WellKnownFolderName.PublicFoldersRoot, folderView);
foreach (var folder in findFolderResults.Where(x => !ignore.Any(i => i == x.DisplayName)))
{
Console.WriteLine(folder.DisplayName);
PrintSubFolder(service, folder.Id, " ");
}
}
private static void PrintSubFolder(ExchangeService service, FolderId folderId, string p)
{
var folderView = new FolderView(int.MaxValue);
var findFolderResults = service.FindFolders(folderId, folderView);
foreach (var folder in findFolderResults.Where(x => !ignore.Any(i => i == x.DisplayName)))
{
Console.WriteLine("{0}{1}", p, folder.DisplayName);
PrintSubFolder(service, folder.Id, p + " ");
}
}
If your using Exchange 2010 or later don't use
var folderView = new FolderView(int.MaxValue);
Throttling will limit the results returned to 1000 so if you expect more the 1000 entries to be return then you'll need to page the results. However it doesn't make much sense to enumerate through every public folder to get the target look at the method in the following link
Searching Of Folders in Public Folders by giving its PATH Name
if the folder is in your mailbox then just do a search for that based on the name eg
FolderView ffView = new FolderView(1000);
ffView.Traversal = FolderTraversal.Deep;
SearchFilter fSearch = new SearchFilter.IsEqualTo(FolderSchema.DisplayName, "xxxx yyyy");
FindFoldersResults ffResults = service.FindFolders(WellKnownFolderName.MsgFolderRoot, fSearch, ffView);
Cheers
Glen
How do i find the folder id of a Skydrive folder using the folder name. Or Is it possible to delete a folder in Skydrive without its folder id.
Am using Windows Phone 8 - LiveConnectClient
-Thanks
I don't think there is a search API but you can do it yourself.
This code is for 5.2 SDK but you get the idea. List the folders in the root folder. If needed list the subfolders till you find the directory.
This is to list the root:
clientFolder.GetAsync("me/skydrive/files");
And to get the ids:
foreach (IDictionary<string, object> album in data)
{
SkydriveAlbum albumItem = new SkydriveAlbum();
albumItem.ID = (string)album["id"];
}
Full code:
/// <summary>
/// Gets the root dirs from SkyDrive
/// </summary>
public void ListSkyDriveRootAlbums()
{
List<SkydriveAlbum> albums = new List<SkydriveAlbum>();
LiveConnectClient clientFolder = new LiveConnectClient(App.Session);
clientFolder.GetCompleted += (sender, e) =>
{
if (e.Error == null)
{
List<object> data = (List<object>)e.Result["data"];
foreach (IDictionary<string, object> album in data)
{
SkydriveAlbum albumItem = new SkydriveAlbum();
albumItem.Title = (string)album["name"];
albumItem.Description = (string)album["description"];
albumItem.ID = (string)album["id"];
albums.Add(albumItem);
}
if (ListAlbumsCompleted != null)
{
ListAlbumsCompleted(albums.ToArray(), e.Error);
}
}
else if (ListAlbumsCompleted != null)
{
ListAlbumsCompleted(null, e.Error);
}
};
clientFolder.GetAsync("me/skydrive/files");
}
How to get all folders name of gmail using ImapX lib?
I read in http://hellowebapps.com/2010-02-09/imapx-net-library-to-manage-imap-folders/ but not found get all folder part.
here is how you get the list of all folders...
FolderCollection folders = client.GetFolders();
foreach (Folder myfolder in folders)
{
MessageBox.Show(myfolder.Name);
}
then use the name with:
ImapX.MessageCollection messages = client.Folders["Spam"].Search("ALL", true);
note that folder name is a case sensitive...
You can iterate the SubFolder collection and can get all of those gamail folders and thier path. An example:
var client = new ImapClient(...);
client.Connection();
client.LogIn(...);
foreach (var item in WalkFolderTree(client.Folders))
{
Console.WriteLine(item.FolderPath);
}
client.LogOut();
You have to custom implement the traversal code like:
public IEnumerable<Folder> WalkFolderTree(FolderCollection folders)
{
foreach (var item in folders)
{
if (item.HasChildren)
{
WalkFolderTree(item.SubFolder);
}
yield return item;
}
}
Then it will list all of the folders like:
INBOX
...
[Gmail]
[Gmail]/All Mail
[Gmail]/Drafts
[Gmail]/Sent Mail
[Gmail]/Spam
[Gmail]/Starred
[Gmail]/Trash
Here's how:
public List<string> getMailboxes(string emailAddress, string emailPassword)
{
var client = new ImapClient("imap.gmail.com", 993, true, true);
if (client.Connect())
{
if (client.Login(emailAddress, emailPassword))
{
//get all parent folers
var folders = client.Folders;
foreach (var parentFolder in folders)
{
//get parent folder path
var parentPath = parentFolder.Path;
//check if every parent folder has subfolder
if (parentFolder.HasChildren)
{
var subfolders = parentFolder.SubFolders;
foreach(var subfolder in subfolders)
{
var subPath = subfolder.Path;
}
}
}
}
}
}