Recursive delete of files and directories in C# - c#

How to delete a given directory recursively in C# ? A directory containing files.
Should the System.IO.Directory.Delete with the second parameter true do the trick?
EDIT:
So, I actually did answer my own question, although the answers here were a little more clarifying. The reason for me asking this in the first place was that the code that has exactly that invocation of Delete (2nd param set to true) was not doing what it was supposed to be doing. As it turned out the cause of that was that there was a file somewhere down in the the directory hierarchy with RO attribute set, and the Polish version of Windows XP was throwing a really strange message for that.

The only solution that worked for me if the subdirectories also contains files is by using a recursive function:
public static void RecursiveDelete(DirectoryInfo baseDir)
{
if (!baseDir.Exists)
return;
foreach (var dir in baseDir.EnumerateDirectories())
{
RecursiveDelete(dir);
}
baseDir.Delete(true);
}
It appears that Directory.Delete(dir, true) only delete files of the current directory, and subdirectories if they are empty.
Hope it helps someone.
btw, example: RecursiveDelete( new DirectoryInfo(#"C:\my_dir") );

Yup, that's the point of that parameter. Did you try it and have any problems? (I've just double-checked, and it works fine for me.)

If you get UnauthorizedAccessException .
You can use modified of RecursiveDelete from Jone Polvora. Thank you for Idea. I will use it.
public static void RecursiveDelete(DirectoryInfo baseDir)
{
if (!baseDir.Exists)
return;
foreach (var dir in baseDir.EnumerateDirectories())
{
RecursiveDelete(dir);
}
var files = baseDir.GetFiles();
foreach (var file in files)
{
file.IsReadOnly = false;
file.Delete();
}
baseDir.Delete();
}

Recursive works for both files and folders (oddly, I thought it didn't work for files; my bad...):
// create some nested folders...
Directory.CreateDirectory(#"c:\foo");
Directory.CreateDirectory(#"c:\foo\bar");
// ...with files...
File.WriteAllText(#"c:\foo\blap.txt", "blup");
File.WriteAllText(#"c:\foo\bar\blip.txt", "blop");
// ...and delete them
Directory.Delete(#"c:\foo", true); // fine

Modified solution from #StayOnTarget, so that root dir is not getting removed:
public static void RecursiveDelete(DirectoryInfo baseDir, bool isRootDir)
{
if (!baseDir.Exists)
return;
foreach (var dir in baseDir.EnumerateDirectories()) RecursiveDelete(dir, false);
foreach (var file in baseDir.GetFiles())
{
file.IsReadOnly = false;
file.Delete();
}
if (!isRootDir) baseDir.Delete();
}

Why do not use?
Directory.Delete(directoryPath, true);
https://msdn.microsoft.com/en-us/library/fxeahc5f(v=vs.110).aspx

Related

Recursive Deletion of Folders in C#

I am trying to recursively delete all empty subdirectories in a root directory and (not files)using C#. I have referred this post (Recursive delete of files and directories in C#)
and wrote the function as follows.
private void DeleteEmptySubFolders()
{
DirectoryInfo root = new DirectoryInfo(folderPath);
RecursiveDelete(root,true);
}
public static void RecursiveDelete(DirectoryInfo baseDir,bool isRootDir)
{
if (!baseDir.Exists)
return;
foreach (var dir in baseDir.EnumerateDirectories())
{
RecursiveDelete(dir,false);
}
try
{
if (!isRootDir)
baseDir.Delete(false);
}
catch(Exception ex)
{
}
}
My question is baseDir.Delete(false); will give me an exception when a directory is not empty, and I am just passing that exception without handling it(I just want to skip those ones, don't have to log). Is there a better way to do this?
Instead of try/catch, check if any files exist:
bool isEmpty = !Directory.EnumerateFileSystemEntries(baseDir.FullName).Any();
Now you can avoid trying to delete non-empty folders:
if (!isRootDir && isEmpty)
baseDir.Delete(false);

DirectoryInfo.Delete vs Directory.Delete

I want to delete the contents of some temp files so I am working on small program that deletes them for me. I have these two code samples but I'm confused as to:
Which code sample is better?
The first sample, code1, deletes the files 1 and 2 but the second sample, code2 will delete the contains of folder 1 and 2?
code1
public void DeleteContains(string Pathz)
{
List<DirectoryInfo> FolderToClear = new List<DirectoryInfo>();
FolderToClear.Add(new DirectoryInfo(#"C:\Users\user\Desktop\1"));
FolderToClear.Add(new DirectoryInfo(#"C:\Users\user\Desktop\2"));
foreach (DirectoryInfo x in FolderToClear)
{
x.Delete(true);
}
}
code 2
private void DeleteContents(string Path)
{
string[] DirectoryList = Directory.GetDirectories(Path);
string[] FileList = Directory.GetFiles(Path);
foreach (string file in FileList)
{
File.Delete(file);
}
foreach ( string directoryin DirectoryList)
{
Directory.Delete(directory, true);
}
}
EDIT: I believe the OP wants a comparison of DirectoryInfo.Delete and Directory.Delete.
If you look at the decompiled source for each method (I used resharper to show me), you can see that DirectoryInfo.Delete and Directory.Delete both call the Delete method with 4 arguments. IMHO, the only difference is that Directory.Delete has to call Path.GetFullPathInternal to get the fullpath. Path.GetFullPathInternal is actually a very long method with lots of checks. Without doing a series of tests for performance, it would be unlikely to determine which is faster and by how much.
Directory.Delete
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
public static void Delete(String path, bool recursive)
{
String fullPath = Path.GetFullPathInternal(path);
Delete(fullPath, path, recursive, true);
}
DirectoryInfo.Delete
[ResourceExposure(ResourceScope.None)]
[ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
public void Delete(bool recursive)
{
Directory.Delete(FullPath, OriginalPath, recursive, true);
}
The first code sample will only delete the folders "C:\Users\user\Desktop\1" and "C:\Users\user\Desktop\2" regardless of what is passed in the parameter.
The second code sample will delete all files and folders that are inside the directory specified by the parameter.

TreeView Where Root And All Nodes Thereafter Are Derived From First Sub-Folder - How To Specify Correct Path?

I am working on a simple, portable, single-form, application where the *.exe and a folder entitled UserGeneratedContent reside in the same directory. On my form I have a treeview that I want to populate with nodes corresponding to all sub-folders (if any exist) of UserGeneratedContent. The code I've pasted in below works almost the way I want it to, but it populates the treeview with UserGeneratedContent as the root node and in turn treats the sub-folders it finds as child nodes, etc.
string folder = #"UserGeneratedContent";
FolderHierachy.Nodes.Add(GetDirectoryNodes(folder));
private static TreeNode GetDirectoryNodes(string path)
{
var node = new TreeNode(Path.GetFileName(path));
var subDirs = Directory.GetDirectories(path).Select(d => GetDirectoryNodes(d)).ToArray();
node.Nodes.AddRange(subDirs);
return node;
}
At this stage I have tried just about every combination of #"UserGeneratedContent" I can think of - adding back-slashes etc, in an attempt to access the sub-folders but I'm having no luck. I know its probably something simple, but I'm stuck - what is the correct syntax to ensure that the method above looks into UserGeneratedContent to get the sub-folders?
Furthermore, I want the treeview control to allow the user to create, rename, and delete folders in any hierachy of their choice so I'm wondering what would be considered best practices in this regard?
Edit \ Update # 1 - 12.2.2012:
After a lot more trial and error I have given up on the code above - no matter what I tried I couldn't get it to work for some reason. Luckily the code below is working perfectly for me :-)
DirectoryInfo dirInfo = new DirectoryInfo(#"UserGeneratedContent");
DirectoryInfo[] subDirs = dirInfo.GetDirectories();
string pathToSubFolders = Path.Combine(#"UserGeneratedContent", subDirs[0].ToString());
PopulateTreeView(treeView1, pathToSubFolders);
private void PopulateTreeView(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())
{
directoryNode.Nodes.Add(CreateDirectoryNode(directory));
}
return directory;
}
I need to add some error handling code to it to allow for there being no sub-folders under #"UserGeneratedContent" - as it is subDirs[0].ToString() throws an IndexOutOfRangeException if no sub-folders exist and I'm not exactly sure how to go about it so I'd be grateful for some pointers.
Edit \ Update # 2 - 12.2.2012:
For my error checking I've used a try-catch block as below:
try
{
string pathToSubFolders = Path.Combine(dirInfo.ToString(), subDirs[0].ToString());
PopulateTreeView(treeView1, pathToSubFolders);
}
catch (IndexOutOfRangeException)
{
//Do Something Here
}
The above code works, but can anyone tell me if I have gone about this the right way?
Thanks for reading.
if you haven't found an other solution yet, a simple way would be:
if(subDirs.Lenght != 0) // or > 0
{
string pathToSubFolders = Path.Combine(dirInfo.ToString(), subDirs[0].ToString());
PopulateTreeView(treeView1, pathToSubFolders);
}
else
{
//Do Something Here
}

Check if DirectoryInfo.FullName is special folder

My goal is to check, if DirectoryInfo.FullName is one of the special folders.
Here is what I'm doing for this (Check directoryInfo.FullName to each special folder if they are equal):
DirectoryInfo directoryInfo = new DirectoryInfo("Directory path");
if (directoryInfo.FullName == Environment.GetFolderPath(Environment.SpecialFolder.Windows) ||
directoryInfo.FullName == Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles ||)
...
...
)
{
// directoryInfo is the special folder
}
But there are many special folders (Cookies, ApplicationData, InternetCache, etc.). Is there any way to do this task more efficiently?
Thanks.
Try this following code :
bool result = false;
DirectoryInfo directoryInfo = new DirectoryInfo("Directory path");
foreach (Environment.SpecialFolder suit in Enum.GetValues(typeof(Environment.SpecialFolder)))
{
if (directoryInfo.FullName == Environment.GetFolderPath(suit))
{
result = true;
break;
}
}
if (result)
{
// Do what ever you want
}
hope this help.
I'm afraid the answers given seem to be the only way, I hate the special folders because what ought to be a very simple function -
void CollectFiles(string strDir, string pattern) {
DirectoryInfo di = new DirectoryInfo(strDir);
foreach(FileInfo fi in di.GetFiles(pattern) {
//store file data
}
foreach(DirectoryInfo diInfo in di.GetDirectories()) {
CollectFiles(diInfo);
}
}
Becomes ugly because you have to include
Check If This Is A Special Folder And Deal With It And Its Child Folders Differently ();
Fair enough Microsoft, to have a folder that could exist anywhere, on a remote PC, on a server etc. But really what is wrong with the UNIX/Linux way, use links to folder and if the destination physical folder has to move, alter the link. Then you can itterate them in a nice neat function treating them all as if ordinary folders.
I don't have enough reputation to add a comment so as a +1 to BobRassler's answer, string comparisons might be more useful.
bool isSpecialFolder = false;
DirectoryInfo directoryInfo = new DirectoryInfo(Path.Combine(tbx_FolderName.Text, fileName));
foreach (Environment.SpecialFolder specialFolder in Enum.GetValues(typeof(Environment.SpecialFolder)))
{
if (directoryInfo.FullName.ToString()
.ToLower() ==
Environment.GetFolderPath(specialFolder)
.ToLower())
{
isSpecialFolder = true;
break;
}
}
if (isSpecialFolder)
{
// something
}
else
{
// something else
}
Use a reflection to get all values from that enum, like here http://geekswithblogs.net/shahed/archive/2006/12/06/100427.aspx and check against collection of generated paths you get.
I ended up using it this way:
public static bool IsSpecialFolder(DirectoryInfo directoryInfo, out Environment.SpecialFolder? _specialFolder) {
bool isSpecialFolder = false;
_specialFolder = null;
string directoryInfo_FullPath = directoryInfo.FullName;
foreach (Environment.SpecialFolder specialFolder in Enum.GetValues(typeof(Environment.SpecialFolder))) {
var specialFolder_FullPath = Environment.GetFolderPath(specialFolder);
if (string.Equals(directoryInfo_FullPath, specialFolder_FullPath, StringComparison.OrdinalIgnoreCase)) {
isSpecialFolder = true;
_specialFolder = specialFolder;
break;
}
}
return isSpecialFolder;
}
If handling strings from dubious sources (the user :-) ), there are three caveats to keep in mind:
Path.Combine vs. Path.Join, since they handle absolute paths (or paths that look like absolute paths) differently.
Path.GetFullPath, which takes a string an produces the full and normalized version of it.
GetFolderPath can return an empty string, which generates a System.ArgumentException: 'The path is empty. (Parameter 'path')' when used for creating a DirectoryInfo.
I like to keep this logic outside the method, but I am not sure if the OrdinalIgnoreCase or any other normalization is still necessary. I guess not.
P.S.: I think in modern lingo the method should be called TrySpecialFolder or something :-)

How to check if a specific file exists in directory or any of its subdirectories

In C#, how do I check if a specific file exists in a directory or any of its subdirectories?
System.IO.File.Exists only seems to accept a single parameter with no overloads to search subdirectories.
I can do it with LINQ and System.IO.Directory.GetFiles using the SearchOption.AllDirectories overload, but that seems a bit heavy handed.
var MyList = from f in Directory.GetFiles(tempScanStorage, "foo.txt", SearchOption.AllDirectories)
where System.IO.Path.GetFileName(f).ToUpper().Contains(foo)
select f;
foreach (var x in MyList)
{
returnVal = x.ToString();
}
If you're looking for a single specific filename, using *.* is indeed heavy handed. Try this:
var file = Directory.GetFiles(tempScanStorage, foo, SearchOption.AllDirectories)
.FirstOrDefault();
if (file == null)
{
// Handle the file not being found
}
else
{
// The file variable has the *first* occurrence of that filename
}
Note that this isn't quite what your current query does - because your current query would find "xbary.txt" if you foo was just bar. I don't know whether that's intentional or not.
If you want to know about multiple matches, you shouldn't use FirstOrDefault() of course. It's not clear exactly what you're trying to do, which makes it hard to give more concrete advice.
Note that in .NET 4 there's also Directory.EnumerateFiles which may or may not perform better for you. I highly doubt that it'll make a difference when you're searching for a specific file (instead of all files in the directory and subdirectories) but it's worth at least knowing about. EDIT: As noted in comments, it can make a difference if you don't have permission to see all the files in a directory.
The alternative is to write the search function yourself, one of these should work:
private bool FileExists(string rootpath, string filename)
{
if(File.Exists(Path.Combine(rootpath, filename)))
return true;
foreach(string subDir in Directory.GetDirectories(rootpath, "*", SearchOption.AllDirectories))
{
if(File.Exists(Path.Combine(subDir, filename)))
return true;
}
return false;
}
private bool FileExistsRecursive(string rootPath, string filename)
{
if(File.Exists(Path.Combine(rootPath, filename)))
return true;
foreach (string subDir in Directory.GetDirectories(rootPath))
{
if(FileExistsRecursive(subDir, filename))
return true;
}
return false;
}
The first method still extracts all of the directory names and would be slower when there are many subdirs but the file is close to the top.
The second is recursive which would be slower in 'worst case' scenarios but faster when there are many nested subdirs but the file is in a top level dir.
To Check for file existing in any specific directory do the following
Note: "UploadedFiles" is name of the folder.
File.Exists(Server.MapPath("UploadedFiles/"))
Enjoy Coding
It is a recursive search on the filesystem. You have some functional examples in CodeProject:
Simple File Search Class (by jabit)
Scan directories using recursion using events (by Jan Schreuder)
This is a recursive search function that will break out as soon as finds the file you've specified. Please note the parameters should be specified as fileName (eg. testdb.bak) and directory (eg. c:\test).
Be aware that this can be quite slow if you do this in a directory with a large quantity of subdirecories and files.
private static bool CheckIfFileExists(string fileName, string directory) {
var exists = false;
var fileNameToCheck = Path.Combine(directory, fileName);
if (Directory.Exists(directory)) {
//check directory for file
exists = Directory.GetFiles(directory).Any(x => x.Equals(fileNameToCheck, StringComparison.OrdinalIgnoreCase));
//check subdirectories for file
if (!exists) {
foreach (var dir in Directory.GetDirectories(directory)) {
exists = CheckIfFileExists(fileName, dir);
if (exists) break;
}
}
}
return exists;
}

Categories

Resources