C#删除所有空子目录

Jay*_*Jay 43 .net c# subdirectory

我有一个清理大量目录的任务.我想从一个目录开始并删除任何不包含文件的子目录(无论多深)(文件永远不会被删除,只有目录).如果起始目录不包含任何文件或子目录,则将删除该起始目录.我希望有人可以指出一些现有的代码,而不是重新发明轮子.我将使用C#来做这件事.

Rag*_*czy 88

使用C#代码.

static void Main(string[] args)
{
    processDirectory(@"c:\temp");
}

private static void processDirectory(string startLocation)
{
    foreach (var directory in Directory.GetDirectories(startLocation))
    {
        processDirectory(directory);
        if (Directory.GetFiles(directory).Length == 0 && 
            Directory.GetDirectories(directory).Length == 0)
        {
            Directory.Delete(directory, false);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 编写`if`语句的更快方法可能是`if(Directory.GetFileSystemEntries(directory).Length == 0)` (14认同)
  • (!Directory.EnumerateFileSystemEntries(目录).Any())更好 (10认同)
  • @ user1985189:这称为递归函数.请参阅:http://en.wikipedia.org/wiki/Recursive_function (4认同)

Joã*_*elo 39

如果您可以定位.NET 4.0,则可以使用Directory类上的新方法枚举目录,以便在您只想知道是否存在至少一个文件时列出目录中的每个文件时不会造成性能损失.

方法是:

  • Directory.EnumerateDirectories
  • Directory.EnumerateFiles
  • Directory.EnumerateFileSystemEntries

使用递归的可能实现:

static void Main(string[] args)
{
    DeleteEmptyDirs("Start");
}

static void DeleteEmptyDirs(string dir)
{
    if (String.IsNullOrEmpty(dir))
        throw new ArgumentException(
            "Starting directory is a null reference or an empty string", 
            "dir");

    try
    {
        foreach (var d in Directory.EnumerateDirectories(dir))
        {
            DeleteEmptyDirs(d);
        }

        var entries = Directory.EnumerateFileSystemEntries(dir);

        if (!entries.Any())
        {
            try
            {
                Directory.Delete(dir);
            }
            catch (UnauthorizedAccessException) { }
            catch (DirectoryNotFoundException) { }
        }
    }
    catch (UnauthorizedAccessException) { }
}
Run Code Online (Sandbox Code Playgroud)

您还提到目录树可能非常深,因此如果您探测的路径太长,可能会出现一些异常.

  • 很好的答案.而不是`if(String.IsNullOrEmpty(entries.FirstOrDefault())``,你也可以使用`if(!entries.Any())`,这是一个更清洁的恕我直言. (2认同)
  • @Danko Durbić,完全同意你的看法,我没有注意到没有参数的重载,并且已经在问自己为什么 `Enumerable` 没有东西可以快速检查空的 `IEnumerable`。谢谢,我更新了答案。 (2认同)

Wol*_*lf5 8

在目前为止提到的3种方法上运行C:\ Windows 1000次测试产生了这样的结果:

GetFiles+GetDirectories:630ms
GetFileSystemEntries:295ms
EnumerateFileSystemEntries.Any:71ms
Run Code Online (Sandbox Code Playgroud)

在空文件夹上运行它会产生这种情况(再次1000次):

GetFiles+GetDirectories:131ms
GetFileSystemEntries:66ms
EnumerateFileSystemEntries.Any:64ms
Run Code Online (Sandbox Code Playgroud)

因此,当您检查空文件夹时,EnumerateFileSystemEntries是最好的整体.


scr*_*dam 5

这是一个利用并行执行的版本,在某些情况下可以更快地完成任务:

public static void DeleteEmptySubdirectories(string parentDirectory){
  System.Threading.Tasks.Parallel.ForEach(System.IO.Directory.GetDirectories(parentDirectory), directory => {
    DeleteEmptySubdirectories(directory);
    if(!System.IO.Directory.EnumerateFileSystemEntries(directory).Any()) System.IO.Directory.Delete(directory, false);
  });   
}
Run Code Online (Sandbox Code Playgroud)

这是单线程模式下的相同代码:

public static void DeleteEmptySubdirectoriesSingleThread(string parentDirectory){
  foreach(string directory in System.IO.Directory.GetDirectories(parentDirectory)){
    DeleteEmptySubdirectories(directory);
    if(!System.IO.Directory.EnumerateFileSystemEntries(directory).Any()) System.IO.Directory.Delete(directory, false);
  }
}
Run Code Online (Sandbox Code Playgroud)

...这里有一些示例代码,您可以使用它来测试场景中的结果:

var stopWatch = new System.Diagnostics.Stopwatch();
for(int i = 0; i < 100; i++) {
  stopWatch.Restart();
  DeleteEmptySubdirectories(rootPath);
  stopWatch.Stop();
  StatusOutputStream.WriteLine("Parallel: "+stopWatch.ElapsedMilliseconds);
  stopWatch.Restart();
  DeleteEmptySubdirectoriesSingleThread(rootPath);
  stopWatch.Stop();
  StatusOutputStream.WriteLine("Single: "+stopWatch.ElapsedMilliseconds);
}
Run Code Online (Sandbox Code Playgroud)

...以下是我的计算机针对广域网文件共享上的目录的一些结果。此共享当前只有 16 个子文件夹和 2277 个文件。

Parallel: 1479
Single: 4724
Parallel: 1691
Single: 5603
Parallel: 1540
Single: 4959
Parallel: 1592
Single: 4792
Parallel: 1671
Single: 4849
Parallel: 1485
Single: 4389
Run Code Online (Sandbox Code Playgroud)