HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Deleting empty files and folders

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
deletingemptyfoldersfilesand

Problem

Tell me how to speed up the removal of empty folders / files ?

string[] dirs = Directory.EnumerateDirectories(str1, "*", SearchOption.AllDirectories).ToArray();
DirectoryInfo dirInfo = new DirectoryInfo(str1);
for (int i = dirs.Length - 1; i >= 0; i--)
{
   if (Directory.EnumerateFileSystemEntries(dirs[i]).Count() == 0)
       Directory.Delete(dirs[i], true);
}
foreach(string pathToFile in Directory.GetFiles(str1))
{
     if (new FileInfo(pathToFile).Length == 0)
     {
          try
          {
              File.Delete(pathToFile);
          }
          catch(Exception ex)
          {
             // error
          }
     } 
}


Deletes files not from all folders.

Solution

Directory.EnumerateDirectories(str1, "*", SearchOption.AllDirectories).ToArray();


Calling ToArray on this is counterproductive because this method returns directory names one by one (in a deferred fasion) as you go and request them. By using ToArray you go over directory names twice. First creating the array and then in your for loop. The EnumerateDirectories is a perfect candidate to be used with Parallel.ForEach or with AsParallel.

For example this is on my machine with 20k empty directories faster by approx 3 sec then the normal loop:

var emptyDirectories = Directory
    .EnumerateDirectories(str1, "*", SearchOption.AllDirectories)
    .AsParallel()
    .Where(d => !Directory.EnumerateFileSystemEntries(d).Any())
    .ToList();


Here you not only take the advantage of the AsParallel but also of the Any that does not have to enumerate all entries but stops as soon as at least one is found.

To delete the empty directories you can use the ForAll extension o a parallel enumeration:

var emptyDirectories =
    from d in Directory.EnumerateDirectories(str1, "*", SearchOption.AllDirectories).AsParallel()
    where !Directory.EnumerateFileSystemEntries(d).Any()
    select d;

emptyDirectories.ForAll(d => { /* delete directory */ });


The above method will of course delete only the last directory. If you want to delete directories that are empty after deleting the last empty directory you need to repeat the process:

var deleted = false;
do
{
    deleted = false;
    emptyDirectories.ForAll(d => { Directory.Delete(d); deleted = true; });
}
while(deleted);


The counterpart of the EnumerateDirectories is the EnumerateFiles method that you can use same way and you can figure out this part yourself ;-)

Code Snippets

Directory.EnumerateDirectories(str1, "*", SearchOption.AllDirectories).ToArray();
var emptyDirectories = Directory
    .EnumerateDirectories(str1, "*", SearchOption.AllDirectories)
    .AsParallel()
    .Where(d => !Directory.EnumerateFileSystemEntries(d).Any())
    .ToList();
var emptyDirectories =
    from d in Directory.EnumerateDirectories(str1, "*", SearchOption.AllDirectories).AsParallel()
    where !Directory.EnumerateFileSystemEntries(d).Any()
    select d;

emptyDirectories.ForAll(d => { /* delete directory */ });
var deleted = false;
do
{
    deleted = false;
    emptyDirectories.ForAll(d => { Directory.Delete(d); deleted = true; });
}
while(deleted);

Context

StackExchange Code Review Q#160527, answer score: 4

Revisions (0)

No revisions yet.