I have an application that displays a treeview of a folders, with the format below:
- Main Folder
- SubFolder
- SubFolder
- SubFolder
- SubFolder
Questions:
1) How do I search for all the folders (not files) and add them to a List called syncDirectories(FIXED)
2) How would I then iterate through my JSON object and save it back to List<SavedData> in order to add/remove data (FIXED)
3) How would I loop through my syncDirectories List and add all the nodes to the TreeView in WPF. (Keep in mind the treeview with checkbox class i am using.
And so on. Also, this is an example to demonstrate the format, and users could have more subdirectories.
Each of these folders has a checkbox on it thanks to this TREEVIEW CLASS.
In order to save all the folders and subfolders the user adds (and checks), I thought saving a JSON file listing all the folder and subfolder paths, along with their (true/false) checked values would be a good idea. Right? I am using Json.NET.
Messing around with some JSON, I came up with this format:
{
"path": "path/here",
"subDirectories": [
{"path": "sub/path/here","sync": false},
{"path": "sub/path/here","sync": true},
{"path": "sub/path/here","sync": false}
]
}
Which translated into the class:
public class SavedData
{
public string path { get; set; }
public List<SubDirectory> subDirectories { get; set; }
}
public class SubDirectory
{
public string path { get; set; }
public bool sync { get; set; }
public List<SubDirectory> subDirectories { get; set; }
}
This raises the question, How do I search for all the folders (not files) and add them to a List called syncDirectories?
Here is what I have so far in my addDirectory function:
private void addDirectory()
{
var dialog = new FolderBrowserDialog();
DialogResult result = dialog.ShowDialog();
if (result == System.Windows.Forms.DialogResult.OK)
{
SavedData data = new SavedData();
data.path = dialog.SelectedPath;
syncedDirectories.Add();
}
// Add the data to syncedDirectories List, then save the list and refresh the treeView
saveData();
}
And the save function:
public void saveData()
{
JsonSerializer serializer = new JsonSerializer();
using (StreamWriter sw = new StreamWriter(appData))
using (JsonWriter writer = new JsonTextWriter(sw))
{
serializer.Serialize(writer, syncedDirectories);
}
}
When I save the data into a file, How would I then iterate through my JSON object and save it back to List<SavedData> in order to add/remove data?
UPDATE 1
I have figured out how to handle my data (Below), but how exactly would i add these "nodes" to the treeview?
public void getDirectories(string dir)
{
// Create the Data Object
SavedData data = new SavedData();
data.path = dir;
data.subDirectories = new List<SubDirectory>();
foreach (string directory in Directory.GetDirectories(dir))
{
SubDirectory subDir = new SubDirectory();
subDir.path = directory;
subDir.subDirectories = getSubDir(directory);
data.subDirectories.Add(subDir);
}
syncedDirectories.Add(data);
}
private List<SubDirectory> getSubDir(string dir)
{
List<SubDirectory> dataList = new List<SubDirectory>();
SubDirectory subDir = new SubDirectory();
foreach (string directory in Directory.GetDirectories(dir))
{
subDir.path = directory;
subDir.subDirectories = new List<SubDirectory>();
subDir.subDirectories = getSubDir(directory);
dataList.Add(subDir);
}
return dataList;
}
Later, i plan to release this program open source on GitHub. When i do, i will post the link here.
After a couple hours of playing around with a function, I realized two functions are needed to complete this task.
public void getDirectories(string dir)
{
// Create the Data Object
SavedData data = new SavedData();
data.path = dir;
data.subDirectories = new List<SubDirectory>();
foreach (string directory in Directory.GetDirectories(dir))
{
SubDirectory subDir = new SubDirectory();
subDir.path = directory;
subDir.subDirectories = getSubDir(directory);
data.subDirectories.Add(subDir);
}
syncedDirectories.Add(data);
}
private List<SubDirectory> getSubDir(string dir)
{
List<SubDirectory> dataList = new List<SubDirectory>();
SubDirectory subDir = new SubDirectory();
foreach (string directory in Directory.GetDirectories(dir))
{
subDir.path = directory;
subDir.subDirectories = new List<SubDirectory>();
subDir.subDirectories = getSubDir(directory);
dataList.Add(subDir);
}
return dataList;
}
This gets the main directory then loops and finds all the subdirectories and adds them to my list.
Related
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;
}
How can I return multiple Arrays with different Values? In my first function I get all files that are in my Folder.
In my second function I extract for each file the "modDesc.xml" and get my Information out of it. Now i want to return for each files a array with all this informations! But i dont know how.. I hope someone can help me!
Here is my code:
public string[] openDirectory(string DirectoryPath)
{
string[] files = Directory.GetFiles(DirectoryPath, "*.zip");
return files;
}
public string[] getModDesc(string DirectoryPath)
{
string[] files = openDirectory(DirectoryPath);
foreach (var file in files)
{
using (ZipFile zip = ZipFile.Read(file))
{
ZipEntry modDescHandler = zip["modDesc.xml"];
if (modDescHandler != null)
{
if (File.Exists("tmp\\modDesc.xml"))
{
File.Delete("tmp\\modDesc.xml");
}
modDescHandler.Extract("tmp");
XDocument modDesc = XDocument.Load("tmp\\modDesc.xml");
string modTitle = null;
string modAuthor = null;
string modVersion = null;
string modFileName = null;
try
{
modTitle = modDesc.Element("modDesc").Element("title").Element("de").Value;
modAuthor = modDesc.Element("modDesc").Element("author").Value;
modVersion = modDesc.Element("modDesc").Element("version").Value;
}
catch
{
}
modFileName = Path.GetFileName(file);
string[] modInformation = { modTitle, modAuthor, modVersion, modFileName };
File.Delete("tmp\\modDesc.xml");
return modInformation;
}
}
}
return new string[0];
}
You could return a List<string[]> (i.e. a list of arrays) which would contain your collection of arrays for each file :
public List<string[]> getModDesc(string DirectoryPath)
{
// Create a list to store your arrays
List<string[]> fileInformation = new List<string[]>();
// Get your files
string[] files = openDirectory(DirectoryPath);
foreach (var file in files)
{
using (ZipFile zip = ZipFile.Read(file))
{
// All your code (omitted for brevity)
// Create your array for this file
string[] modInformation = { modTitle, modAuthor, modVersion, modFileName };
// Add this to your list
fileInformation.Add(modInformation);
}
}
// At this point your arrays collection should have all of your
// arrays, so return it
return fileInformation;
}
}
Or if your file names were each unique and you wanted to make accessing them a bit easier, you could store them in a Dictionary that would allow you to look each one up by it's name :
public Dictionary<string,string[]> getModDesc(string DirectoryPath)
{
// Create a list to store your arrays
Dictionary<string,string[]> fileInformation = new Dictionary<string,string[]>();
// Get your files
string[] files = openDirectory(DirectoryPath);
foreach (var file in files)
{
using (ZipFile zip = ZipFile.Read(file))
{
// All your code (omitted for brevity)
// Create your array for this file
string[] modInformation = { modTitle, modAuthor, modVersion, modFileName };
// Add this to your dictionary, mapping the file name
// to it's information
fileInformation.Add(modFileName,modInformation);
}
}
// At this point your dictionary should have all of your
// arrays, so return it
return fileInformation;
}
}
Then, if you wanted to access the information from a file in your dictionary, you could simply use :
string[] information = yourDictionary["YourFileName"];
The task is to implement a recursive enumeration of subdirectories and files for chosen directory.
4 threads:
1st - primary(Application.Run()); 2nd - scans the chosen directory and writes files to some publicly available collection (I do not understand in which one);
3rd - receives from the 2nd thread the information about subdirectory or a file from "publicly availiable collection" and stores the result in xml file (asynchronously). To keep the hierarchy of the directory;
4th - receives from the 2nd thread the information about subdirectory or a file from "publicly availiable collection" and stores the result in treeView (asynchronously). To keep the hierarchy of the directory;
There is a method that performs a recursive search.
private void WalkDirectoryTree(System.IO.DirectoryInfo root)
{
System.IO.FileInfo[] files = null;
System.IO.DirectoryInfo[] subDirs = null;
try
{
files = root.GetFiles("*.*");
}
// than the application provides.
catch (UnauthorizedAccessException e)
{
log.Add(e.Message);
}
catch (System.IO.DirectoryNotFoundException e)
{
Console.WriteLine(e.Message);
}
if (files != null)
{
if (count > 0)
{
//i have introduced variable: count = 0 for understanding, in which
//direction are we moving through the hierarchy: top or down
tn[count] = tn[count - 1].Nodes.Add(root.Name.ToString() + " " + count);
list.Add(new CustomClass(root.Name, count));
}
//textBox1.AppendText("Directory: "+root.Name+"\n");
count++;
foreach (System.IO.FileInfo fi in files)
{
//textBox1.AppendText(fi.Name +fi.CreationTime+fi.Length+ "\n");
list.Add(new CustomClass(fi.Name,count));
tn[count] = tn[count - 1].Nodes.Add(fi.Name +" " + count);
}
subDirs = root.GetDirectories();
foreach (System.IO.DirectoryInfo dirInfo in subDirs)
{
WalkDirectoryTree(dirInfo);
count--;
}
}
}
i have also the method where i stacked at: method that stores result(subdirectory or file to the xml file)
private void WriteToXML()
{
textBox1.Clear();
doc = new XDocument(new XElement("Folder","Oreh"));
// root element is created manually, because i can't implement corrctly
// this method even in this way!
int newcount = 1;
//newcount is a variable with the help of which i can define the direction
//of moving though the hierarchy by comparing with l.ParentID(count in prev. method)
xElem[newcount] = doc.Root;
foreach (var l in list)
{
if (l.ParentID > newcount)
{
xElem[newcount +1] = new XElement("Name", l.Name,new Attribute("ID",l.ParentID));
xElem[newcount].Add(xElem[newcount+ 1]);
newcount=l.ParentID;
}
else if (l.ParentID < newcount)
{
newcount --;
xElem[newcount - 1] = new XElement("Name", l.Name, new XAttribute("ID", l.ParentID));
xElem[newcount].Add(xElem[newcount - 1]);
}
else
{
xElem[newcount].Add(new XElement("Name", l.Name, new XAttribute("ID", l.ParentID)));
}
}
doc.Save("Tree.xml");
}
The problem is: i don't know in which collection and how should i store the result, obtained from WalkDirectoryTree() method and how to write this result into xml file.
I would implement a class to simplify things and information. THIS IS AN EXAMPLE. You need to read how to manage null Parents or Zero Directories inside a directory. Consider this some kind of pseudocode
class DirInfo
{
public string ParentDir { get; set; };
public string DirName { get; set; };
public string[] files { get; set; };
public DirectoryInfo[] Dirs = null { get; set; };
}
List<DirInfo> Directories = new List<DirInfo>();
//We don't really know the amount
//unless we iterate through it, so you can make an array []
private void DirSearch(System.IO.DirectoryInfo Root)
{
//You need to add you own validations when parent is null, or not subdirectories inside or 0 files inside, etc.
Directories.Add(new DirInfo() { ParentDir = Root.Parent.Name, DirName = Root.Name, files = Root.GetFiles("*.*"), Dirs = Root.GetDirectories() };
if(Root.Dirs != null)
for(int i=0; i<Root.Dirs.Lenght; i++){
DirSearch(Root.Dirs[i]);
}
}
After this, you will have a list with Directories information like:
RootDir { Parent: N/A -> Name: RootDir -> Files: ... File1, FIle2... -> SubDirs: Dir1... Dir2... }
Dir1 { Parent: RootDir -> Name: Dir1 -> Files... ... -> SubDirs: DirSub1, DirSub2... }
DirSub1 { Parent: Dir1 -> Name: DirSub1 -> Files... ... -> SubDirs: Etc, Etc... }
Now, you can create an array of dirs, by sorting them... You can select each directory where it's parent is RootDir, Dir1, etc...
I have the following recursion code to get all the folders and files of a selected directory. But when I select a drive, for example E:\\ .., I am getting an error message of
"Access denied in accessing E:\system volume information"
Is it possible to bypass the system volume information folder?
This is the code I am using:
private static ArrayList GenerateFileList(string Dir)
{
ArrayList fils = new ArrayList();
bool Empty = true;
foreach (string file in Directory.GetFiles(Dir)) // add each file in directory
{
fils.Add(file);
Empty = false;
}
if (Empty)
{
if (Directory.GetDirectories(Dir).Length == 0)
// if directory is completely empty, add it
{
fils.Add(Dir + #"/");
}
}
foreach (string dirs in Directory.GetDirectories(Dir)) // recursive
{
foreach (object obj in GenerateFileList(dirs))
{
fils.Add(obj);
}
}
return fils; // return file list
}
private static ArrayList GenerateFileList(string Dir)
{
ArrayList fils = new ArrayList();
bool Empty = true;
try
{
foreach (string file in Directory.GetFiles(Dir)) // add each file in directory
{
fils.Add(file);
Empty = false;
}
}
catch(UnauthorizedAccessException e)
{
// I believe that's the right exception to catch - compare with what you get
return new ArrayList();
}
if (Empty)
{
if (Directory.GetDirectories(Dir).Length == 0)
// if directory is completely empty, add it
{
fils.Add(Dir + #"/");
}
}
foreach (string dirs in Directory.GetDirectories(Dir)) // recursive
{
foreach (object obj in GenerateFileList(dirs))
{
fils.Add(obj);
}
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;
}