The code below returns only the most recent value in the loop. What do I need to do for it to show all the values that are being iterated over? The reason I am using this method instead of SearchOption.AllDirectory is because there is a folder path I am not able to access. I did try using UnauthorizedAccessException with a try and catch, but that returns an empty value because it keeps on terminating the loop.
public void Main()
{
string path = #"drive"; // TODO
ApplyAllFiles(path, ProcessFile);
}
public void ProcessFile(string path)
{
/* ... */
}
public void ApplyAllFiles(string folder, Action<string> fileAction)
{
System.Collections.ArrayList FileList = new System.Collections.ArrayList();
List<string> logger = new List<string>();
DateTime DateFilter = DateTime.Now.AddMonths(-6);
foreach (string file in Directory.GetDirectories(folder))
{
fileAction(file);
}
foreach (string subDir in Directory.GetDirectories(folder))
{
string rootfolder = "root folder";
if (subDir.Contains(rootfolder))
{
FileList.Add(subDir);
Dts.Variables["User::objDirectoryList"].Value = FileList;
//MessageBox.Show(subDir);
}
try
{
ApplyAllFiles(subDir, fileAction);
}
catch (UnauthorizedAccessException e)
{
logger.Add(e.Message);
}
catch (System.IO.DirectoryNotFoundException e)
{
logger.Add(e.Message);
}
}
}
Try to remove the FileList declaration outside the function, also remove Dts.Variables["User::objDirectoryList"].Value = FileList; outside the loop:
System.Collections.ArrayList FileList = new System.Collections.ArrayList();
public void Main()
{
string path = #"drive"; // TODO
ApplyAllFiles(path, ProcessFile);
Dts.Variables["User::objDirectoryList"].Value = FileList;
}
public void ProcessFile(string path)
{
/* ... */
}
public void ApplyAllFiles(string folder, Action<string> fileAction)
{
List<string> logger = new List<string>();
DateTime DateFilter = DateTime.Now.AddMonths(-6);
foreach (string file in Directory.GetDirectories(folder))
{
fileAction(file);
}
foreach (string subDir in Directory.GetDirectories(folder))
{
string rootfolder = "root folder";
if (subDir.Contains(rootfolder))
{
FileList.Add(subDir);
//MessageBox.Show(subDir);
}
try
{
ApplyAllFiles(subDir, fileAction);
}
catch (UnauthorizedAccessException e)
{
logger.Add(e.Message);
}
catch (System.IO.DirectoryNotFoundException e)
{
logger.Add(e.Message);
}
}
}
Related
I bumped into the problem with copying files/dirs. Been struggling almost for whole day.
I have to copy from root dir files and its dires with files and subdirs.
Actually, i've made something. However, every time i run in the stackoverflow error.
abstract class SystemOperations {
public virtual void SearchFiles() { }
public virtual void SearchDirectories() { }
public abstract void CreateDirectory(string DIR);
public abstract void CloneContent(string DIR);
public abstract void CreateJSON(string DIR);
public void ExecuteCopying(string DIR) {
CreateDirectory(DIR);
CloneContent(DIR);
CreateJSON(DIR);
}
}
class FileOperations : SystemOperations {
DirectoryInfo _MainPath;
public DirectoryInfo MainPath {
get { return _MainPath; }
set { _MainPath = value; }
}
public FileOperations(DirectoryInfo MainPath) {
this.MainPath = MainPath;
}
#region Unnecessary for current task
public override void SearchFiles() {
string path = "";
FileInfo[] files = MainPath.GetFiles();
foreach (FileInfo file in files) {
path = file.Name;
}
}
public override void SearchDirectories() {
string path = "";
DirectoryInfo[] directories = MainPath.GetDirectories();
foreach (DirectoryInfo directory in directories) {
path = directory.Name;
}
}
#endregion
public override void CreateDirectory(string DIR) {
string newFolder = Path.Combine(MainPath + "", DIR);
Directory.CreateDirectory(newFolder);
}
public override void CloneContent(string DIR) {
foreach (var directory in Directory.GetDirectories(MainPath + "")) {
string dir = Path.GetFileName(directory);
CloneContent(Path.Combine(MainPath + "", dir));
}
foreach (var file in Directory.GetFiles(MainPath + "")) {
File.Copy(file, Path.Combine(MainPath + "", Path.GetFileName(file)), true);
}
}
public override void CreateJSON(string DIR) {
if (!Directory.Exists(DIR)) {
var asd = new DirectoryInfo(DIR);
}
}
}
class Program {
static void Main() {
SystemOperations task = new FileOperations(new DirectoryInfo(#"D:\\LAK"));
task.ExecuteCopying("COPY");
}
}
So, the function CloneContent has to copy in each dir/subdirs files. But its recursive func and as i written above, i run to the error. And dont know how to fix this one. Thank u!
There is some kind of problem with the way you are trying to determine which directory you need to search next, the use of MainPath looks wrong to me.
Personally i also always prefer to have a secondary stop condition to avoid a StackOverflowException, like the maxrunCount i use below.
If you want a recursive directory lookup you should rewrite your code to something like
void Main()
{
string MainPath = "D:\\LAK";
// unless your directory is actually named \LAK:) you should use either #"D:\LAK" or "d:\\LAK"
CloneContent(MainPath,1000);
}
public void CloneContent(string directoryToSearch, int maxrunCount)
{
if(maxrunCount==0)
return;
System.Diagnostics.Debug.Print(directoryToSearch);
string[] directories = null;
try
{
directories = Directory.GetDirectories(directoryToSearch);
}
catch(UnauthorizedAccessException ex) {
System.Diagnostics.Debug.Print($"No access to dir {directoryToSearch}");
directories = new string[0];
}
// ensure you have access to the current directoryToSearch
foreach (var directory in directories)
{
CloneContent(directory,--maxrunCount);
}
System.Diagnostics.Debug.Print($"cloning {directoryToSearch}");
// .... do the actual cloning here,
// you will end up here when there are no more subdirectories on the current branch
}
For a recursive method to work, it must have at least one "exit" condition - the point at which it's done its job and can unwind the stack. In our case, it would be when there are no more direcories or files to copy from the source to the destination.
One way of writing this method would take in a source directory and a destination directory, and then it can recursively call itself for each sub-directory:
public static void CloneContent(string sourceDir, string destDir)
{
// If the source directory doesn't exist, return
if (!Directory.Exists(sourceDir)) return;
// Create destination if needed
Directory.CreateDirectory(destDir);
// Copy files from this directory to the new path
foreach (string file in Directory.GetFiles(sourceDir))
{
File.Copy(file, Path.Combine(destDir, Path.GetFileName(file)));
}
// Recursively call this method for each sub directory
foreach (string subDir in Directory.GetDirectories(sourceDir))
{
string dirName = Path.GetFileName(subDir);
string newSource = Path.Combine(sourceDir, dirName);
string newDest = Path.Combine(destDir, dirName);
CloneContent(newSource, newDest);
}
}
static IEnumerable<string> GetSubdirectoriesContainingOnlyFiles(string path)
{
try
{
return from subdirectory in Directory.GetDirectories(path, "*", SearchOption.AllDirectories)
where Directory.GetDirectories(subdirectory).Length == 0
select subdirectory;
}
catch
{
}
}
In this case i'm searching in c:\
So some directories are access denied. I added try and catch but now this method dosent have a return.
And how or should i handle at all it when it's getting to the catch ?
I want in the end to get a List of all sub directories so i can get all sub directories names and the Length(the number of sub directories).
UPDATE
I tried this in the class constructor:
if (m_pars.SearchDir != null)
{
ApplyAllFiles(m_pars.SearchDir,ProcessFile);
}
m_pars.SearchDir in this contain C:\
Then in ApplyAllFiles:
static List<string> allsubdirs = new List<string>();
static void ProcessFile(string path) {/* ... */}
public 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);
allsubdirs.Add(subDir);
}
catch
{
// swallow, log, whatever
}
}
}
But the List allsubdirs is empty.
Your problem might be that you don't visit (add to the list) the current directory before recursively visiting its subdirectories. So if you get an exception there, nothing will be added to the list.
The following works for me. (I've also made it a bit more generic by using callbacks and made the exception handling stricter.)
class DirectoryHelper
{
public static void Test()
{
DirectoryHelper.EnumerateSubDirectories(#"c:\windows\system32");
}
public static List<string> EnumerateSubDirectories(string path)
{
// Depending on your use case, it might be
// unecessary to save these in memory
List<string> allSubdirs = new List<string>();
EnumerateSubDirectories(path,
filePath => Console.WriteLine("Visited file: " + filePath),
dirPath => allSubdirs.Add(dirPath),
noAccessPath => Console.WriteLine("No access: " + noAccessPath)
);
return allSubdirs;
}
private static void EnumerateSubDirectories(string root, Action<string> fileAction, Action<string> subdirAction, Action<string> noAccessAction)
{
foreach (string file in Directory.GetFiles(root))
{
fileAction(file);
}
foreach (string dir in Directory.GetDirectories(root))
{
try
{
subdirAction(dir);
EnumerateSubDirectories(dir, fileAction, subdirAction, noAccessAction);
}
catch (UnauthorizedAccessException)
{
noAccessAction(dir);
}
}
}
}
I want to Load Directory Structure Into TreeView. If there is a txt file in folder it must be break. Child folders and files should not shown. Please help me to find an algorithm
private void ListDirectory(TreeView treeView, string path)
{
treeView.Nodes.Clear();
var rootDirectoryInfo = new DirectoryInfo(path);
treeView.Nodes.Add(CreateDirectoryNode(rootDirectoryInfo));
}
private static TreeNode CreateDirectoryNode(DirectoryInfo directoryInfo)
{
var directoryNode = new TreeNode(directoryInfo.Name);
foreach (var directory in directoryInfo.GetDirectories())
{
if (directory.Name.EndsWith("txt"))
{
break;
}
else
{
directoryNode.Nodes.Add(CreateDirectoryNode(directory));
}
}
foreach (var file in directoryInfo.GetFiles())
{
if (directoryNode.Name.EndsWith("txt"))
{
directoryNode.Nodes.Add(new TreeNode(file.Name));
}
}
return directoryNode;
}
I solved it like that,
private static TreeNode CreateDirectoryNode(DirectoryInfo directoryInfo)
{
var directoryNode = new TreeNode(directoryInfo.Name);
try
{
int flag = 0;
foreach (var file in directoryInfo.GetFiles())
{
if (file.Name.EndsWith("txt"))
{
flag = 1;
}
}
if (flag == 0)
{
foreach (var directory in directoryInfo.GetDirectories())
{
directoryNode.Nodes.Add(CreateDirectoryNode(directory));
}
}
return directoryNode;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return null;
}
}
Summary Of Problem:
I have a console app that, after copying many folders and files over to a new location, a local drive, it then deletes certain files/folders. One of these filetypes it deletes is .exe files. When trying to delete said files it gives me a denied access error.(This also occurs while trying to delete other kinds of files and folders as well)
Other Notes:
I saw several questions, such as Unable to delete .exe file through c#. However the process was never running on my local machine nor on the source it was copied from. I am both a local administrator and a domain administrator on our domain, and I had ownership over all folders and files in the directories I'm working with. But it still denies me access when trying to delete the file from code. I am however able to delete such files/folders manually.(click delete key)
Problem:
As stated above I am looking for a way to get past this issue denying me access to delete these "Illegal" file types and delete them from my code.
My Code:(Updated)
#region Delete_Illegal_Items
public static void RemoveIllegalItems()
{
Console.Clear();
DirectoryInfo Libraries = new DirectoryInfo(Library.DestinationMain);
try
{
foreach (var Lib in Libraries.GetDirectories())
{
Console.WriteLine("Working On {0}.", Lib.Name);
Parallel.Invoke(
() =>
{
RemoveBadFiles(Lib);
},
() =>
{
DeleteEmptyFolders(Lib);
}
);
}
}
catch (AggregateException e)
{
Console.WriteLine("There Was An Unusual Error During Initialization Of Library Correction:\n{0}", e.InnerException.ToString());
}
}
private static string[] BadFiles = {
#".hta",
#".exe",
#".lnk",
#".tmp",
#".config",
#".ashx",
#".hta.",
#".hta::$DATA",
#".zip",
#".asmx",
#".json",
#".soap",
#".svc",
#".xamlx",
#".msi",
#".ops",
#".pif",
#".shtm",
#".shtml",
#"smt",
#".vb",
#".vbe",
#".vbs",
#".ds_store",
#".db",
#".ini",
#".tiff"
};
private static void RemoveBadFiles(DirectoryInfo directory)
{
DirectoryInfo[] dirs = null;
FileInfo[] files = null;
if (directory != null)
{
files = directory.GetFiles();
}
try
{
dirs = directory.GetDirectories();
}
catch (IOException) { }
catch (Exception e)
{
Console.WriteLine("\nError During Enumeration Of Items To Delete:\n{0}", e.Message);
}
if (files != null)
{
foreach (var file in files)
{
try
{
if (file.IsReadOnly)
{
file.IsReadOnly = false;
}
if (BadFiles.Contains(Path.GetExtension(file.FullName)))
{
File.Delete(file.FullName);
}
}
catch (Exception e)
{
Console.WriteLine("\nError During Removal Or Illegal Files:\n" + e.Message);
}
}
}
if (dirs != null)
{
foreach (var dir in dirs)
{
switch (dir.Name)
{
case ".TemporaryItems":
{
try
{
Directory.Delete(dir.FullName);
}
catch { }
break;
}
case "AI_RecycleBin":
{
try
{
Directory.Delete(dir.FullName);
}
catch { }
break;
}
case ".ToRemove":
{
try
{
Directory.Delete(dir.FullName);
}
catch { }
break;
}
default:
{
break;
}
}
RemoveBadFiles(dir);
}
}
}
private static void DeleteEmptyFolders(DirectoryInfo directory)
{
Program Main = new Program();
try
{
DirectoryInfo[] dirs = directory.GetDirectories();
foreach (var subDirectory in dirs)
{
int sum = Library.CountLibrary(subDirectory.FullName);
if (sum == 0)
{
Directory.Delete(subDirectory.FullName);
}
DeleteEmptyFolders(subDirectory);
}
}
catch { }
}
#endregion
Any help would be greatly appreciated. If this question has been directly answered elsewhere please feel free to mention it in the comment. As I stated above I have been looking through past question regarding this issue and have not found a solution as of yet. Otherwise thank you for your help.
Figured out the problem was with the files being marked as "Read-only" so I added a if statement before the deletion of the file to check if it was and remove the mark if need be. Here is the code that worked successfully for deleting all the wanted files.
#region Delete_Illegal_Items
public static void RemoveIllegalItems()
{
Console.Clear();
DirectoryInfo Libraries = new DirectoryInfo(Library.DestinationMain);
try
{
foreach (var Lib in Libraries.GetDirectories())
{
Console.WriteLine("Working On {0}.", Lib.Name);
Parallel.Invoke(
() =>
{
RemoveBadFiles(Lib);
},
() =>
{
DeleteEmptyFolders(Lib);
}
);
}
}
catch (AggregateException e)
{
Console.WriteLine("There Was An Unusual Error During Initialization Of Library Correction:\n{0}", e.InnerException.ToString());
}
}
private static string[] BadFiles = {
#".hta",
#".exe",
#".lnk",
#".tmp",
#".config",
#".ashx",
#".hta.",
#".hta::$DATA",
#".zip",
#".asmx",
#".json",
#".soap",
#".svc",
#".xamlx",
#".msi",
#".ops",
#".pif",
#".shtm",
#".shtml",
#"smt",
#".vb",
#".vbe",
#".vbs",
#".ds_store",
#"ds_store",
#"._.Trashes",
#".Trashes",
#".db",
#".dat",
#".sxw",
#".ini",
#".tif",
#".tiff"
};
private static void RemoveBadFiles(DirectoryInfo directory)
{
DirectoryInfo[] dirs = null;
FileInfo[] files = null;
if (directory != null)
{
try
{
files = directory.GetFiles();
}
catch (IOException) { }
}
try
{
dirs = directory.GetDirectories();
}
catch (IOException) { }
catch (Exception e)
{
Console.WriteLine("\nError During Enumeration Of Items To Delete:\n{0}", e.Message);
}
if (files != null)
{
foreach (var file in files)
{
try
{
if (file.IsReadOnly)
{
file.IsReadOnly = false;
}
if (BadFiles.Contains(Path.GetExtension(file.FullName)) || BadFiles.Contains(file.Name))
{
File.Delete(file.FullName);
}
}
catch (Exception e)
{
Console.WriteLine("\nError During Removal Or Illegal Files:\n" + e.Message);
}
}
}
if (dirs != null)
{
foreach (var dir in dirs)
{
switch (dir.Name)
{
case ".TemporaryItems":
{
try
{
Directory.Delete(dir.FullName);
}
catch { }
break;
}
case "TemporaryItems":
{
try
{
Directory.Delete(dir.FullName);
}
catch { }
break;
}
case "AI_RecycleBin":
{
try
{
Directory.Delete(dir.FullName);
}
catch { }
break;
}
case ".ToRemove":
{
try
{
Directory.Delete(dir.FullName);
}
catch { }
break;
}
default:
{
break;
}
}
RemoveBadFiles(dir);
}
}
}
private static void DeleteEmptyFolders(DirectoryInfo directory)
{
Program Main = new Program();
try
{
DirectoryInfo[] dirs = directory.GetDirectories();
foreach (var subDirectory in dirs)
{
int sum = Library.CountLibrary(subDirectory.FullName);
if (sum == 0)
{
Directory.Delete(subDirectory.FullName);
}
DeleteEmptyFolders(subDirectory);
}
}
catch { }
}
#endregion
Thank you to those that comment and helped. And hope this can help others in the future.
I am creating an application which finds duplication in files. When I search files like:
try
{
string[] allFiles = Directory.GetFiles(
directoryPath, "*.*", SearchOption.AllDirectories
);
for (int i = 0; i < allFiles.Length; i++)
{
//decisions
}
}
catch (UnauthorizedAccessException ex)
{
MessageBox.Show(ex.Message);
}
it says
Access to path 'C:\$Recycle.Bin....... ' is denied.
I want if a folder is not accessible then move to the next but execution of program stops at Directory.GetFiles method.
Here's a class that will work:
public static class FileDirectorySearcher
{
public static IEnumerable<string> Search(string searchPath, string searchPattern)
{
IEnumerable<string> files = GetFileSystemEntries(searchPath, searchPattern);
foreach (string file in files)
{
yield return file;
}
IEnumerable<string> directories = GetDirectories(searchPath);
foreach (string directory in directories)
{
files = Search(directory, searchPattern);
foreach (string file in files)
{
yield return file;
}
}
}
private static IEnumerable<string> GetDirectories(string directory)
{
IEnumerable<string> subDirectories = null;
try
{
subDirectories = Directory.EnumerateDirectories(directory, "*.*", SearchOption.TopDirectoryOnly);
}
catch (UnauthorizedAccessException)
{
}
if (subDirectories != null)
{
foreach (string subDirectory in subDirectories)
{
yield return subDirectory;
}
}
}
private static IEnumerable<string> GetFileSystemEntries(string directory, string searchPattern)
{
IEnumerable<string> files = null;
try
{
files = Directory.EnumerateFileSystemEntries(directory, searchPattern, SearchOption.TopDirectoryOnly);
}
catch (UnauthorizedAccessException)
{
}
if (files != null)
{
foreach (string file in files)
{
yield return file;
}
}
}
}
You can the use it like this:
IEnumerable<string> filesOrDirectories = FileDirectorySearcher.Search(#"C:\", "*.txt");
foreach (string fileOrDirectory in filesOrDirectories)
{
// Do something here.
}
It's recursive, but the use of yield gives it a low memory footprint (under 10KB in my testing). If you want only files that match the pattern and not directories as well just replace EnumerateFileSystemEntries with EnumerateFiles.