DirectoryInfo.Delete vs Directory.Delete - c#

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.

Related

C# function does not stop after returning the value

I have this function, that should find full filename from given root directory and file name.
static string WalkDirectoryTree(DirectoryInfo root, string fileName)
{
FileInfo[] files = null;
DirectoryInfo[] subDirs = null;
files = root.GetFiles("*.*");
string fullFileName = "";
string rnd = "";
if (files != null)
{
foreach (FileInfo file in files)
{
if(file.Name == fileName)
{
Console.WriteLine("Success!");
fullFileName = file.FullName;
rnd = file.Name;
return fullFileName;
}
}
subDirs = root.GetDirectories();
foreach (DirectoryInfo dirInfo in subDirs)
{
if (rnd == fileName)
{
break;
}
else
{
WalkDirectoryTree(dirInfo, fileName);
}
}
}
return fullFileName;
}
I was looking how this code executes with help of breakpoints. It finds the searched file name and it enters that if statement (below)
if(file.Name == fileName)
{
Console.WriteLine("Success!");
fullFileName = file.FullName;
rnd = file.Name;
return fullFileName;
}
By following along execution I also found out, that it does execute the return step in if statement above, and after that goes straight to the end of the function, but then, it continues to execute that function again and again, until it has gone through all the subdirectories in given root directory. And obviously, it overwrites returning value and it is not what this function was intended to do.
Can someone spot the problem and suggest any solution to this?
As others have pointed out, you're calling a recursive function so you're getting a lot of calls to WalkDirectoryTree and each one is returning one and only one value, but because of the many calls it appears like the one call is still going.
I did want to give you an alternative that might provide you with some food-for-thought on how to tackle this kind of problem in the future.
The key thing that you're recursing is the traversal of your directory structure. If you start with a method that just does that.
static IEnumerable<DirectoryInfo> WalkDirectoryTree(DirectoryInfo root)
{
yield return root;
foreach (var di1 in root.GetDirectories())
foreach (var di2 in WalkDirectoryTree(di1))
yield return di2;
}
That just returns all of the directories starting with root and recursing down the directory structure until it runs out of directories. It's lazily evaluated so it only returns as many directories as you ask for. That's useful when you go looking for your file as it will stop listing directories once it finds your file.
Now the search function is simple and non-recursive.
static string FindTheFile(DirectoryInfo root, string fileName)
{
foreach (var di in WalkDirectoryTree(root))
foreach (var fi in di.GetFiles())
if (fi.Name == fileName)
return fi.FullName;
return String.Empty;
}
I hope this helps.
Congratulations, you've found a tree-walking problem which may be better served by an explicit stack than recursive function calls.
While it is possible to inspect the return value of recursive calls as several people have commented, there's a price associated with that. Here's a better alternative:
static string WalkDirectoryTree(DirectoryInfo root, string fileName)
{
var to_process = new Stack<DirectoryInfo>();
to_process.Push(root);
while (to_process.TryPop(out var dir))
{
foreach (FileInfo file in dir.GetFiles(filename))
{
if(file.Name == fileName)
{
Console.WriteLine("Success!");
return file.FullName;
}
}
foreach (DirectoryInfo subdir in dir.GetDirectories())
{
to_process.Push(subdir);
}
}
return null; // no matches
}
This will do a depth-first search just like the recursive version, but it won't use multiple frames on the call stack, so the first match can return immediately to the original caller, while the recursive version returned to itself one directory level up. Do note that the search will go in the reverse order that subdirectories are returned from GetDirectories() due to using a LIFO stack... if important this can be changed by reversing the GetDirectories() results before looping and pushing.
I've also changed the filespec passed to dir.GetFiles from *.* to filename, since you aren't interested in all files in the directory. I didn't take out the case-sensitive string equality test, but you probably don't want that either.
Still, it's a good idea to learn to write and debug recursive code. When stepping through in the debugger, make sure to have your "Call Stack" debugger window open, and when you hit a return statement watch that Call Stack window carefully.
Finally, this recursive search is built into the framework. Simply
return root.EnumerateFiles(fileName, SearchOption.AllDirectories).FirstOrDefault();
is sufficient to perform a recursive search that stops at the first match (unlike passing the same SearchOption.AllDirectories to GetFiles() which will wastefully find every match in the whole directory tree)
Really, the only reason for writing this yourself, apart from the experience gained, is to avoid the pitfall mentioned in the documentation:
If you choose AllDirectories in your search and the directory structure contains a link that creates a loop, the search operation enters an infinite loop.
When writing the tree walk yourself, it's possible to do something about this problem (although the improved code presented above still ignores this situation)
The problem is in your call to WalktDirecotryTree. You don't check it's return value, so you need to bail if that returns what you wanted.

get all files within path (recursion)

I wrote a method that needed to find all files within a path, and I want to get all the files using recursion. Here's my current method:
public void doStart(DirectoryInfo dir, string filePattern)
{
try
{
foreach (FileInfo fileInfo in dir.GetFiles(filePattern))
{
if (fileFound != null)
{
fileFound(fileInfo);
}
}
}
catch (Exception)
{
}
try
{
foreach (DirectoryInfo dirInfo in dir.GetDirectories())
{
doStart(dirInfo, filePattern);
}
}
catch (Exception)
{
}
}
public void Start(string path, string filePattern)
{
doStart(new DirectoryInfo(path), filePattern);
}
Is there is better way to write this kind of recursion or is this good enough ?
Try something like this:
string[] filePaths = Directory.GetFiles(#dir, "*.filetype", SearchOption.AllDirectories);
This would recursively look through the directory, finding all files with a certain filetype ('.filetype') and returns a string array containing all found files.
Also, I'd recommend not to use empty catch blocks, as your application won't let you know if something went wrong. Either show a message box (or something similar) or log it to a database or something.
Further, what would your DoStart() method do if there is a subdirectory in a subdirectory? From what I'm seeing, I'd say it only searches on 1 sublevel.
Don't swallow all exceptions. If you need to ignore specific exceptions, catch those but let others bubble up
(style) Methods should be PascalCased (e.g. DoStart and `FileFound'
(style) Create an OnFileFound method instead of calling FileFound directly (I assume fileFound is an event handler?)
Other than that it looks fine to me.
Here is an example of true recursion. This will search until there are no more sub-directories to find, unlike Directory.GetFiles SearchOption.AllDirectories. You can modify this to add search filters as a parameter.
public IEnumerable<string> GetFilesRecursive(string ParentDirectory)
{
string[] subDirectories = Directory.GetDirectories(ParentDirectory);
foreach (string file in Directory.GetFiles(ParentDirectory))
{
yield return file;
}
foreach (string subDirectory in subDirectories)
{
foreach (string file in GetFilesRecursive(subDirectory))
{
yield return file;
}
}
}

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;
}

How do I get a directory size (files in the directory) in C#?

I want to be able to get the size of one of the local directories using C#. I'm trying to avoid the following (pseudo like code), although in the worst case scenario I will have to settle for this:
int GetSize(Directory)
{
int Size = 0;
foreach ( File in Directory )
{
FileInfo fInfo of File;
Size += fInfo.Size;
}
foreach ( SubDirectory in Directory )
{
Size += GetSize(SubDirectory);
}
return Size;
}
Basically, is there a Walk() available somewhere so that I can walk through the directory tree? Which would save the recursion of going through each sub-directory.
A very succinct way to get a folder size in .net 4.0 is below. It still suffers from the limitation of having to traverse all files recursively, but it doesn't load a potentially huge array of filenames, and it's only two lines of code. Make sure to use the namespaces System.IO and System.Linq.
private static long GetDirectorySize(string folderPath)
{
DirectoryInfo di = new DirectoryInfo(folderPath);
return di.EnumerateFiles("*.*", SearchOption.AllDirectories).Sum(fi => fi.Length);
}
If you use Directory.GetFiles you can do a recursive seach (using SearchOption.AllDirectories), but this is a bit flaky anyway (especially if you don't have access to one of the sub-directories) - and might involve a huge single array coming back (warning klaxon...).
I'd be happy with the recursion approach unless I could show (via profiling) a bottleneck; and then I'd probably switch to (single-level) Directory.GetFiles, using a Queue<string> to emulate recursion.
Note that .NET 4.0 introduces some enumerator-based file/directory listing methods which save on the big arrays.
Here my .NET 4.0 approach
public static long GetFileSizeSumFromDirectory(string searchDirectory)
{
var files = Directory.EnumerateFiles(searchDirectory);
// get the sizeof all files in the current directory
var currentSize = (from file in files let fileInfo = new FileInfo(file) select fileInfo.Length).Sum();
var directories = Directory.EnumerateDirectories(searchDirectory);
// get the size of all files in all subdirectories
var subDirSize = (from directory in directories select GetFileSizeSumFromDirectory(directory)).Sum();
return currentSize + subDirSize;
}
Or even nicer:
// get IEnumerable from all files in the current dir and all sub dirs
var files = Directory.EnumerateFiles(searchDirectory,"*",SearchOption.AllDirectories);
// get the size of all files
long sum = (from file in files let fileInfo = new FileInfo(file) select fileInfo .Length).Sum();
As Gabriel pointed out this will fail if you have a restricted directory under the searchDirectory!
You could hide your recursion behind an extension method (to avoid the issues Marc has highlighted with the GetFiles() method):
public static class UserExtension
{
public static IEnumerable<FileInfo> Walk(this DirectoryInfo directory)
{
foreach(FileInfo file in directory.GetFiles())
{
yield return file;
}
foreach(DirectoryInfo subDirectory in directory.GetDirectories())
{
foreach(FileInfo file in subDirectory.Walk())
{
yield return file;
}
}
}
}
(You probably want to add some exception handling to this for protected folders etc.)
Then:
using static UserExtension;
long totalSize = 0L;
var startFolder = new DirectoryInfo("<path to folder>");
// iteration
foreach(FileInfo file in startFolder.Walk())
{
totalSize += file.Length;
}
// linq
totalSize = di.Walk().Sum(s => s.Length);
Basically the same code, but maybe a little neater...
First, forgive my poor english ;o)
I had a problem that took me to this page : enumerate files of a directory and his subdirectories without blocking on an UnauthorizedAccessException, and, like the new method of .Net 4 DirectoryInfo.Enumerate..., get the first result before the end of the entire query.
With the help of various examples found here and there on the web, I finally write this method :
public static IEnumerable<FileInfo> EnumerateFiles_Recursive(this DirectoryInfo directory, string searchPattern, SearchOption searchOption, Func<DirectoryInfo, Exception, bool> handleExceptionAccess)
{
Queue<DirectoryInfo> subDirectories = new Queue<DirectoryInfo>();
IEnumerable<FileSystemInfo> entries = null;
// Try to get an enumerator on fileSystemInfos of directory
try
{
entries = directory.EnumerateFileSystemInfos(searchPattern, SearchOption.TopDirectoryOnly);
}
catch (Exception e)
{
// If there's a callback delegate and this delegate return true, we don't throw the exception
if (handleExceptionAccess == null || !handleExceptionAccess(directory, e))
throw;
// If the exception wasn't throw, we make entries reference an empty collection
entries = EmptyFileSystemInfos;
}
// Yield return file entries of the directory and enqueue the subdirectories
foreach (FileSystemInfo entrie in entries)
{
if (entrie is FileInfo)
yield return (FileInfo)entrie;
else if (entrie is DirectoryInfo)
subDirectories.Enqueue((DirectoryInfo)entrie);
}
// If recursive search, we make recursive call on the method to yield return entries of the subdirectories.
if (searchOption == SearchOption.AllDirectories)
{
DirectoryInfo subDir = null;
while (subDirectories.Count > 0)
{
subDir = subDirectories.Dequeue();
foreach (FileInfo file in subDir.EnumerateFiles_Recursive(searchPattern, searchOption, handleExceptionAccess))
{
yield return file;
}
}
}
else
subDirectories.Clear();
}
I use a Queue and a recursive method to keep traditional order (content of directory and then content of first subdirectory and his own subdirectories and then content of the second...). The parameter "handleExceptionAccess" is just a function call when an exception is thrown with a directory; the function must return true to indicate that the exception must be ignored.
With this methode, you can write :
DirectoryInfo dir = new DirectoryInfo("c:\\temp");
long size = dir.EnumerateFiles_Recursive("*", SearchOption.AllDirectories, (d, ex) => true).Sum(f => f.Length);
And here we are : all exception when trying to enumerate a directory will be ignore !
Hope this help
Lionel
PS : for a reason I can't explain, my method is more quick than the framework 4 one...
PPS : you can get my test solutions with source for those methods : here TestDirEnumerate. I write EnumerateFiles_Recursive, EnumerateFiles_NonRecursive (use a queue to avoid recursion) and EnumerateFiles_NonRecursive_TraditionalOrder (use a stack of queue to avoid recursion and keep traditional order). Keep those 3 methods has no interest, I write them only for test the best one. I think to keep only the last one.
I also wrote the equivalent for EnumerateFileSystemInfos and EnumerateDirectories.
Have a look at this post:
http://social.msdn.microsoft.com/forums/en-US/vbgeneral/thread/eed54ebe-facd-4305-b64b-9dbdc65df04e
Basically there is no clean .NET way, but there is a quite straightforward COM approach so if you're happy with using COM interop and being tied to Windows, this could work for you.
the solution is already here https://stackoverflow.com/a/12665904/1498669
as in the duplicate How do I Get Folder Size in C#? shown -> you can do this also in c#
first, add the COM reference "Microsoft Scripting Runtime" to your project and use:
var fso = new Scripting.FileSystemObject();
var folder = fso.GetFolder(#"C:\Windows");
double sizeInBytes = folder.Size;
// cleanup COM
System.Runtime.InteropServices.Marshal.ReleaseComObject(folder);
System.Runtime.InteropServices.Marshal.ReleaseComObject(fso);
remember to cleanup the COM references
I've been looking some time ago for a function like the one you ask for and from what I've found on the Internet and in MSDN forums, there is no such function.
The recursive way is the only I found to obtain the size of a Folder considering all the files and subfolders that contains.
You should make it easy on yourself. Make a method and passthrough the location of the directory.
private static long GetDirectorySize(string location) {
return new DirectoryInfo(location).GetFiles("*.*", SearchOption.AllDirectories).Sum(file => file.Length);
}
-G

Recursive delete of files and directories in 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

Categories

Resources