I am writing a tool that will allow me to go though a fairly large list of Directories and Sub-directories. I would like it to delete a folder if there it is empty. I can delete folders and sub folders that are empty with this code:
string dir = textBox1.Text;
string[] folders = System.IO.Directory.GetDirectories(dir, "*.*", System.IO.SearchOption.AllDirectories);
foreach (var directory in folders)
{
if (System.IO.Directory.GetFiles(directory).Length == 0 && System.IO.Directory.GetDirectories(directory).Length == 0)
{
System.IO.StreamWriter Dfile = new System.IO.StreamWriter(newpath, true);
System.IO.Directory.Delete(directory);
}
}
My question is how to have the code go though and check the folders after each delete because once it deletes a folder it could make the parent folder empty and should then should be deleted. Once the code does not find any folders or sub-folders that are empty it would exit.
Write a depth-first recursive function. As you complete each recursive call, check the current folder to see if it is empty. If it is, then delete it.
Something like this (pseudocode)
DeleteEmptyFolders(path)
{
foreach Folder f in Path
{
DeleteEmptyFolders(f);
if (f is empty)
{
Delete(f);
}
}
}
You can do this recursively like this (not tested):
void DeleteFolder(string folder) {
string[] folders = System.IO.Directory.GetDirectories(folder, "*.*", System.IO.SearchOption.AllDirectories);
foreach (var directory in folders)
{
DeleteFolder(directory);
}
//delete this folder if empty
}
Here's an idea (this isn't tested)
while ( true )
{
DirectoryInfo parent = Directory.GetParent(current.FullName);
if ( parent.GetFiles().Length == 0 && parent.GetDirectories().Length == 0 )
{
current = parent;
current.Delete();
}
else
{
break;
}
}
This walks up the tree of the current directory to delete any parent directories that are empty.
By the look of it your are trying to delete any folder which does not contain a file. I believe this would do the trick for you. I tested it with a small folder set that went 5 levels deep and a single file in a couple of locations. All folders which did not have files were deleted. All files were left intact. Small tweak to a snippet found... Thanks Matt Smith.
Cannot delete directory with Directory.Delete(path, true)
string[] dirs = System.IO.Directory.GetDirectories(Directory.GetCurrentDirectory(), "*.*",SearchOption.AllDirectories);
foreach (string d in dirs)
{
if (System.IO.Directory.Exists(d)) {
if (System.IO.Directory.GetFiles(d, "*.*", SearchOption.AllDirectories).Length == 0)
{
DeleteDirectory(d);
}
}
}
public static void DeleteDirectory(string target_dir)
{
string[] dirs = Directory.GetDirectories(target_dir);
foreach (string dir in dirs)
{
DeleteDirectory(dir);
}
Directory.Delete(target_dir, false);
}
this will delete all empty (sub)folders in a given directory
https://stackoverflow.com/a/16688997/2408998
Related
I'm trying to check whether a directory is in a format of
Ex:
This should be valid:
D:\TESTDIR\FOLDER1\FOLDER2\Somerandomfiles
This is not valid:
D:\TESTDIR\FOLDER1\Somerandomfiles
Basically I need to make sure that for every folder there should be a subfolder inside. note that a single folder may contain multiple subfolder. Then the subfolder will contain the files such as text files/pdf files etc.
//not sure how/where to place to check if folder has a subfolder
var _dir = Directory.GetDirectories(#"D:\TESTDIR");
foreach(var _folder1 in _dir)
{
// check if contains folder2? if not
// MessageBox.Show(folder1name);
var _folder2 = Directory.GetDirectories(_folder1);
foreach (var _path in _folder2)
{
// do something
}
}
You almost got it right, I just modified your code a little:
var dir = Directory.GetDirectories(#"D:\TESTDIR");
foreach(var folder1 in dir)
{
var folder2 = Directory.GetDirectories(folder1);
// If no directories are found in that subfolder, skip it.
// Basically it would work the same without if, as loop
// would not run even one iteration, but it's more readable.
if(folder2.Count == 0) continue;
foreach (var path in folder2)
{
var files = Directory.GetFiles(path);
// Same as above, check if there are any files.
if(files.Count == 0) break;
// Do some work
}
}
Here's how I would start this:
var query =
from dir in Directory.GetDirectories(#"D:\TESTDIR")
select new
{
dir,
valid =
Directory.GetDirectories(dir).Any()
&& Directory.GetDirectories(dir).All(child => Directory.GetFiles(child).Any())
};
That's going to check each of the directories in #"D:\TESTDIR" and ensure each has at least one subfolder and that each subfolder has at least one file.
I have a simple function that deletes every file and folder in a target directory. I want to blacklist some directories so that this delete function will not perform the deletion on any file or folder inside any of these directories. Also, it should't delete sub-directories in this directory.
I used a list to represent the blacklisted directories:
private string[] blacklistedFolders =
{
"C:/Program Files",
"C:/Program Files (x86)",
"C:/ProgramData",
"C:/Users",
"C:/Windows"
};
The code that deletes items in a directory:
bool IsBacklisted(string targetDir)
{
for (int i = 0; i < blacklistedFolders.Length; i++)
{
string bList = blacklistedFolders[i];
//Check if the targetDir contains the target directory
if (bList.Contains(targetDir))
return true;
}
return false;
}
public void EmptyDirectory(string targetDir)
{
//Exit if path is blacklisted
if (IsBacklisted(targetDir))
return;
DirectoryInfo dInfo = new DirectoryInfo(targetDir);
foreach (FileInfo fileInfo in dInfo.GetFiles())
{
fileInfo.Delete();
}
foreach (DirectoryInfo dirInfo in dInfo.GetDirectories())
{
dirInfo.Delete(true);
}
}
The problem is that I'am worried that this blacklisted part of the code might fail resulting to the files and folders from the blacklisted directory being deleted. Maybe the blacklist check may not match on different platforms due to the presence of "/" or "\" at the end or middle of the path or other scenarios I may have missed.
Is there a built-in System.IO function or a better way to do this check other that the String.Contains function I am currently using to check for blacklisted directories?
In my program I have a treeview and a folderbrowser and a datagridview. The user uses the folder browser to choose a folder which contains bunch of shows which all have different seasons. My program displays the folders for the shows and the season folders inside them in the treeview and each time the select a folder from treeview I want it to display all the files inside that folder. I am currectly using this code:
public void fileProcessDirectory(string targetDirectory, string Name)
{
string[] fileEntries = Directory.GetFiles(targetDirectory);
foreach (string fileName in fileEntries)
{
FileProcessFile(fileName);
}
string[] subdirectoryEntries = Directory.GetDirectories(targetDirectory);
foreach (string subdirectory in subdirectoryEntries)
{
fileProcessDirectory(subdirectory, Name);
break;
}
}
public void FileProcessFile(string path)
{
dataGridView.Rows.Add(path, "New");
}
it shows the files inside the first sub folder that I have. it used to show all the files inside all the folders so I added a break and now it shows the first 3 files and stops there. So I want it to display the files inside the selected subfolder not all the sub folders.
You can try to modify your function as this:
public void FileProcessDirectory(string targetDirectory, string subfolder)
{
// this adds files
foreach (string fileName in Directory.GetFiles(targetDirectory))
{
FileProcessFile(fileName);
}
// if we pass subfolder as empty then nothing happens
if(string.IsNullOrEmpty(subfolder)) return;
// here we find our subfolder and display files for it
FileProcessDirectory(Directory.GetDirectories(targetDirectory).Where(d => d == targetDirectory + "\\" + subfolder).ToArray()[0], null);
}
And the ussage example:
FileProcessDirectory(Directory.GetParent(Directory.GetCurrentDirectory()).FullName, "Debug");
Please correct my understanding if I'm wrong:
user select the folder, then on treeview select the season then they should see in the data grid view all the files inside, correct ?
I implemented in this way
treeView1.NodeMouseDoubleClick += new TreeNodeMouseClickEventHandler(treeView1_NodeMouseClick);
if user double click on the treenode it shows all the files inside in the data grid:
void treeView1_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
if (treeView1.SelectedNode != null)
{
dataGridView1.Rows.Clear();
string[] fileEntries = System.IO.Directory.GetFiles(treeView1.SelectedNode.Text);
foreach (string fileName in fileEntries)
{
dataGridView1.Rows.Add(Path.GetFileName(fileName));
}
}
}
I guess the problem before maybe caused by the dataGrid not clearing the old files. Hope it helps.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
DirectoryInfo.Delete vs Directory.Delete
I made this code to empty some files that I regularly delete, such as temp and MSN cahes files in Windows.
code1
I can add new paths to apply DeleteContains method in easy way I just have to add the path to the list
code2
will not allow me to add paths as much I want and I have to create new array of string for each path and a new loop too
anyway to use code1 to delete contains of the folder NOT the folder and its contains??
any work around in the foreach in code1 to work as code2 ??
Because some Folder can be delete or deleting them will cause problem for some apps and the apps wont work again it like
"C:\Users\user\AppData\Local\Temp"
while other folder can be delete it with no problem like MSN cashes
"C:\Users\user\AppData\Local\Microsoft\Windows Live\Contacts"
code1
private void Clear_Click(object sender, EventArgs e)
{
List<DirectoryInfo> FolderToClear = new List<DirectoryInfo>();
// here is a list of files I want to delete
FolderToClear.Add(new DirectoryInfo("path1"));
FolderToClear.Add(new DirectoryInfo("path2"));
FolderToClear.Add(new DirectoryInfo("path3"));
FolderToClear.Add(new DirectoryInfo("path4"));
foreach (DirectoryInfo directory in FolderToClear)
{
directory.Delete(true);
}
}
code2
private void DeleteContents(string Path)
{
string[] DirectoryList = Directory.GetDirectories(Path1);
string[] FileList = Directory.GetFiles(Path1);
foreach (string xin FileList)
{
File.Delete(x);
}
foreach ( string x in DirectoryList)
{
Directory.Delete(x, true);
}
}
Try:
DirectoryInfo directory = new DirectoryInfo("Path");
foreach (FileInfo fi in directory.GetFiles())
{
fi.Delete();
}
Better yet, here is a recursive that will delete all the files and sub directories under the DirectoryInfo you provide.
Note: There is nothing in here to handle file locks so it will bomb if you have th file open. This should get you started.
public void KeepTheseFolders(DirectoryInfo dirInfo)
{
DeleteFolder(new DirectoryInfo("Path1"), false);
DeleteFolder(new DirectoryInfo("Path2"), false);
DeleteFolder(new DirectoryInfo("Path3"), false);
DeleteFolder(new DirectoryInfo("Path4"), false);
}
public void DeleteFolder(DirectoryInfo dirInfo, bool deleteDirectory)
{
//Check for sub Directories
foreach (DirectoryInfo di in dirInfo.GetDirectories())
{
//Call itself to delete the sub directory
DeleteFolder(di, true);
}
//Delete Files in Directory
foreach (FileInfo fi in dirInfo.GetFiles())
{
fi.Delete();
}
//Finally Delete Empty Directory if optioned
if (deleteDirectory)
{
dirInfo.Delete();
}
}
Added it so you can keep your original folder
Listing all files in a drive other than my system drive throws an UnauthorizedAccessException.
How can I solve this problem?
Is there a way to grant my application the access it needs?
My code:
Directory.GetFiles("S:\\", ...)
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.
Are you allowed to access the drive? Can the program access the drive when it's not run from Visual Studio? Are restrictive permissions defined in the project's Security page ("Security Page, Project Designer")?
In .net core you can do something like this below. It can search for all subdirectories recursively with good performance and ignoring paths without access.
I also tried other methods found in
How to quickly check if folder is empty (.NET)? and
Is there a faster way than this to find all the files in a directory and all sub directories? and
https://www.codeproject.com/Articles/1383832/System-IO-Directory-Alternative-using-WinAPI
public static IEnumerable<string> ListFiles(string baseDir)
{
EnumerationOptions opt = new EnumerationOptions();
opt.RecurseSubdirectories = true;
opt.ReturnSpecialDirectories = false;
//opt.AttributesToSkip = FileAttributes.Hidden | FileAttributes.System;
opt.AttributesToSkip = 0;
opt.IgnoreInaccessible = true;
var tmp = Directory.EnumerateFileSystemEntries(baseDir, "*", opt);
return tmp;
}
I solved the problem. Not really but at least the source.
It was the SearchOption.AllDirectories option that caused the exception.
But when I just list the immediate files using Directories.GetFiles, it works.
This is good enough for me.
Any way to solve the recursive listing problem?