C# 删除所有空子目录

问题描述 投票:0回答:10

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

c# .net subdirectory
10个回答
117
投票

使用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);
        }
    }
}

55
投票

如果您可以针对 .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) { }
}

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


12
投票

对目前提到的 3 种方法在 C:\Windows 上运行测试 1000 次,结果如下:

GetFiles+GetDirectories:630ms
GetFileSystemEntries:295ms
EnumerateFileSystemEntries.Any:71ms

在空文件夹上运行它会产生以下结果(再次运行 1000 次):

GetFiles+GetDirectories:131ms
GetFileSystemEntries:66ms
EnumerateFileSystemEntries.Any:64ms

因此,当您检查空文件夹时,EnumerateFileSystemEntries 是迄今为止最好的整体。


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

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

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

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

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

...这是我的机器针对广域网文件共享上的目录的一些结果。此共享当前只有 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
    

3
投票
从这里开始,

用于删除空目录的Powershell脚本:

$items = Get-ChildItem -Recurse foreach($item in $items) { if( $item.PSIsContainer ) { $subitems = Get-ChildItem -Recurse -Path $item.FullName if($subitems -eq $null) { "Remove item: " + $item.FullName Remove-Item $item.FullName } $subitems = $null } }

注意:使用风险自负!


3
投票
如果你依赖

DirectoryInfo.Delete

只删除空目录,你可以写一个简洁的扩展方法

public static void DeleteEmptyDirs(this DirectoryInfo dir) { foreach (DirectoryInfo d in dir.GetDirectories()) d.DeleteEmptyDirs(); try { dir.Delete(); } catch (IOException) {} catch (UnauthorizedAccessException) {} }

用途:

static void Main() { new DirectoryInfo(@"C:\temp").DeleteEmptyDirs(); }
    

1
投票
private static void deleteEmptySubFolders(string ffd, bool deleteIfFileSizeZero=false) { DirectoryInfo di = new DirectoryInfo(ffd); foreach (DirectoryInfo diSon in di.GetDirectories("*", SearchOption.TopDirectoryOnly)) { FileInfo[] fis = diSon.GetFiles("*.*", SearchOption.AllDirectories); if (fis == null || fis.Length < 1) { diSon.Delete(true); } else { if (deleteIfFileSizeZero) { long total = 0; foreach (FileInfo fi in fis) { total = total + fi.Length; if (total > 0) { break; } } if (total == 0) { diSon.Delete(true); continue; } } deleteEmptySubFolders(diSon.FullName, deleteIfFileSizeZero); } } }
    

0
投票
//Recursive scan of empty dirs. See example output bottom string startDir = @"d:\root"; void Scan(string dir, bool stepBack) { //directory not empty if (Directory.GetFileSystemEntries(dir).Length > 0) { if (!stepBack) { foreach (string subdir in Directory.GetDirectories(dir)) Scan(subdir, false); } } //directory empty so delete it. else { Directory.Delete(dir); string prevDir = dir.Substring(0, dir.LastIndexOf("\\")); if (startDir.Length <= prevDir.Length) Scan(prevDir, true); } } //call like this Scan(startDir, false); /*EXAMPLE outputof d:\root with empty subfolders and one filled with files Scanning d:\root Scanning d:\root\folder1 (not empty) Scanning d:\root\folder1\folder1sub1 (not empty) Scanning d:\root\folder1\folder1sub1\folder2sub2 (deleted!) Scanning d:\root\folder1\folder1sub1 (deleted!) Scanning d:\root\folder1 (deleted) Scanning d:\root (not empty) Scanning d:\root\folder2 (not empty) Scanning d:\root\folder2\folder2sub1 (deleted) Scanning d:\root\folder2 (not empty) Scanning d:\root\folder2\notempty (not empty) */
    

0
投票
foreach (var folder in Directory.GetDirectories(myDir, "*", System.IO.SearchOption.AllDirectories)) { { try { if (Directory.GetFiles(folder, "*", System.IO.SearchOption.AllDirectories).Length == 0) Directory.Delete(folder, true); } catch { } } }
    

0
投票
foreach (var emptyDir in Directory.GetDirectories(root,"*",SearchOption.AllDirectories) .Select(p=>new DirectoryInfo(p)) .Where(p=>p.GetFiles("*.*", SearchOption.AllDirectories).Count() == 0)) { emptyDir.Delete(); }
    
© www.soinside.com 2019 - 2024. All rights reserved.