简体   繁体   English

如何删除所有文件/文件夹但将根文件夹保留在 C# 中

[英]How to delete all files/folders but keep the root folder in C#

I wrote some code to recursively delete all file/folders in .Net and it works, but I want to keep the root folder.我写了一些代码来递归删除 .Net 中的所有文件/文件夹,它可以工作,但我想保留根文件夹。 Is there way to modify the folder delete condition (Directory.GetFiles(sPath).Length == 0 && Directory.GetDirectories(sPath).Length == 0) to know it's the root folder and not delete it even though there are no files/folders left in the root?有没有办法修改文件夹删除条件 (Directory.GetFiles(sPath).Length == 0 && Directory.GetDirectories(sPath).Length == 0) 以知道它是根文件夹并且即使没有文件也不删除它/文件夹留在根目录?

void CleanupFiles(String sPath, int iDayDelAge)
{
    if (iDayDelAge != 0) // enabled?
    {
        // Check for aged files to remove
        foreach (String file in Directory.GetFiles(sPath))
        {
            FileInfo fi = new FileInfo(file);
            if (fi.LastWriteTime < DateTime.Now.AddDays(iDayDelAge * -1))  // overdue?
            {
                fi.Delete();
            }
        }

        // Recursively search next subfolder if available
        foreach (String subfolder in Directory.GetDirectories(sPath))
        {
            CleanupFiles(subfolder, iDayDelAge);
        }

        // Remove empty folder
        if (Directory.GetFiles(sPath).Length == 0 && Directory.GetDirectories(sPath).Length == 0)
        {
            Directory.Delete(sPath);
        }
    }
}

Change the code a little bit.稍微修改一下代码。 Add a new argument root, and pass it as false on the recursive calls.添加一个新参数 root,并在递归调用中将其作为 false 传递。

static void Main(string[] args)
{
    CleanupFiles(xxx, xxx, true);
}

void CleanupFiles(String sPath, int iDayDelAge, bool root)
{
    if (iDayDelAge != 0) // enabled?
    {
        // Check for aged files to remove
        foreach (String file in Directory.GetFiles(sPath))
        {
            FileInfo fi = new FileInfo(file);
            if (fi.LastWriteTime < DateTime.Now.AddDays(iDayDelAge * -1))  // overdue?
            {
                fi.Delete();
            }
        }

        // Recursively search next subfolder if available
        foreach (String subfolder in Directory.GetDirectories(sPath))
        {
            CleanupFiles(subfolder, iDayDelAge, false);
        }

        // Remove empty folder
        if (Directory.GetFiles(sPath).Length == 0 && Directory.GetDirectories(sPath).Length == 0 && !root)
        {
            Directory.Delete(sPath);
        }
    }
}

I wouldn't mess around with recursive deleting.我不会乱用递归删除。 And use the DirectoryInfo class to delete the directories.并使用DirectoryInfo类删除目录。

void CleanupFiles(String sPath, int iDayDelAge)
{
    if (iDayDelAge == 0) // enabled?
    {
        return;
    }  

    // Check for aged files to remove
    foreach (String file in Directory.GetFiles(sPath))
    {
        FileInfo fi = new FileInfo(file);
        if (fi.LastWriteTime < DateTime.Now.AddDays(iDayDelAge * -1))  // overdue?
        {
            fi.Delete();
        }
    }

    foreach (String subfolder in Directory.GetDirectories(sPath))
    {
        var dirInfo = new DirectoryInfo(subfolder);
        dirInfo.Delete(true); 
    }
}

You can also rely on API provided by Microsoft instead of explicit recursion:您还可以依赖 Microsoft 提供的 API 而不是显式递归:

foreach (var file in Directory.GetFiles(sPath))
{
    File.Delete(file);
}

foreach (var directory in Directory.GetDirectories(sPath, "*", SearchOption.TopDirectoryOnly))
{
     Directory.Delete(directory, true);
}

This should first delete all files in your root directory (spath) and later recursively delete all subdirectories along with content.这应该首先删除根目录(spath)中的所有文件,然后递归删除所有子目录和内容。

This example should work as you described.这个例子应该像你描述的那样工作。

    public static void Main() {
        var start = new DirectoryInfo( @"C:\Temp\Test" );
        CleanupFiles( start, 5, true );
    }

    /// <summary>
    /// <para>Remove any files last written to <paramref name="daysAgo"/> or before.</para>
    /// <para>Then recursively removes any empty sub-folders, but not the starting folder (when <paramref name="isRootFolder"/> is true).</para>
    /// <para>Attempts to remove any old read-only files also.</para>
    /// </summary>
    /// <param name="directory"></param>
    /// <param name="daysAgo"></param>
    /// <param name="isRootFolder"></param>
    /// <param name="removeReadOnlyFiles"></param>
    public static void CleanupFiles( [NotNull] DirectoryInfo directory, int daysAgo, Boolean isRootFolder, Boolean removeReadOnlyFiles = true ) {
        if ( directory == null ) {
            throw new ArgumentNullException( paramName: nameof( directory ) );
        }

        if ( daysAgo < 1 ) {
            return;
        }

        directory.Refresh();

        if ( !directory.Exists ) {
            return;
        }

        var before = DateTime.UtcNow.AddDays( -daysAgo );

        // Check for aged files to remove
        Parallel.ForEach( directory.EnumerateFiles().AsParallel().Where( file => file.LastWriteTimeUtc <= before ), file => { 
            if ( file.IsReadOnly ) {
                if ( removeReadOnlyFiles ) {
                    file.IsReadOnly = false;
                }
                else {
                    return;
                }
            }

            file.Delete();
        } );

        foreach ( var subfolder in directory.EnumerateDirectories() ) {
            CleanupFiles( subfolder, daysAgo, false, removeReadOnlyFiles );
        }

        if ( !isRootFolder ) {
            if ( !directory.EnumerateDirectories().Any() && !directory.EnumerateFiles().Any() ) {
                directory.Delete();
            }
        }
    }
}

I wanted to see how the async version of this would work.我想看看它的异步版本是如何工作的。 Here you go.干得好。

public class Program {
    public static async Task Main( String[] args ) {
        await TestCleaningFolders.Test().ConfigureAwait(false);
    }
}

public class TestCleaningFolders {

    public static async Task Test() {
        var start = new DirectoryInfo( @"T:\Temp\Test" );
        var cancel = new CancellationTokenSource();
        var olderThan = DateTime.UtcNow.AddDays( -5 );
        var onException = new Action<Exception>( exception => Console.WriteLine( exception.ToString() ) ); //could easily be other logging or something..

        await CleanupFilesAsync( start, olderThan, deleteEmptyFolders: true, removeReadOnlyFiles: true, onException: onException, token: cancel.Token )
            .ConfigureAwait( false );
    }

    /// <summary>
    ///     <para>Remove any files last written to on or before <paramref name="olderThan" />.</para>
    ///     <para>Then recursively removes any empty sub-folders, but not the starting folder (when <paramref name="deleteEmptyFolders" /> is true).</para>
    ///     <para>Attempts to remove any old read-only files also.</para>
    /// </summary>
    /// <param name="folder"></param>
    /// <param name="olderThan"></param>
    /// <param name="deleteEmptyFolders"></param>
    /// <param name="removeReadOnlyFiles"></param>
    /// <param name="onException"></param>
    /// <param name="token"></param>
    [NotNull]
    public static Task CleanupFilesAsync( [NotNull] DirectoryInfo folder, DateTime olderThan, Boolean deleteEmptyFolders, Boolean removeReadOnlyFiles,
        [CanBeNull] Action<Exception> onException, CancellationToken token ) {

        if ( folder is null ) {
            throw new ArgumentNullException( nameof( folder ) );
        }

        return Task.Run( async () => {

            folder.Refresh();

            if ( folder.Exists ) {
                if ( ScanAndRemoveOldFiles() ) {
                    await ScanIntoSubFolders().ConfigureAwait( false );
                    RemoveFolderIfEmpty();
                }
            }
        }, token );

        void Log<T>( T exception ) where T : Exception {
            Debug.WriteLine( exception.ToString() );

            if ( Debugger.IsAttached ) {
                Debugger.Break();
            }

            onException?.Invoke( exception );
        }

        Boolean ScanAndRemoveOldFiles() {
            try {
                foreach ( var file in folder.EnumerateFiles().TakeWhile( info => !token.IsCancellationRequested ) ) {

                    RemoveFileIfOld( file );

                    if ( token.IsCancellationRequested ) {
                        return false; //Added another check because a delete operation itself can take time (where a cancel could be requested before the next findfile).
                    }
                }
            }
            catch ( UnauthorizedAccessException exception ) {
                Log( exception );

                return false;
            }
            catch ( SecurityException exception ) {
                Log( exception );

                return false;
            }
            catch ( DirectoryNotFoundException exception ) {
                Log( exception );

                return false;
            }
            catch ( IOException exception ) {
                Log( exception );
            }

            return true;
        }

        void RemoveFileIfOld( FileInfo fileInfo ) {
            if ( fileInfo is null ) {
                throw new ArgumentNullException( paramName: nameof( fileInfo ) );
            }

            try {
                if ( !fileInfo.Exists || fileInfo.LastWriteTimeUtc > olderThan ) {
                    return;
                }

                if ( fileInfo.IsReadOnly ) {
                    if ( removeReadOnlyFiles ) {
                        fileInfo.IsReadOnly = false;
                    }
                    else {
                        return;
                    }
                }

                fileInfo.Delete();
            }
            catch ( FileNotFoundException exception ) {
                Log( exception );
            }
            catch ( SecurityException exception ) {
                Log( exception );
            }
            catch ( UnauthorizedAccessException exception ) {
                Log( exception );
            }
            catch ( IOException exception ) {
                Log( exception );
            }
        }

        async Task ScanIntoSubFolders() {
            try {
                foreach ( var subfolder in folder.EnumerateDirectories().TakeWhile( info => !token.IsCancellationRequested ) ) {
                    await CleanupFilesAsync( subfolder, olderThan, deleteEmptyFolders: true, removeReadOnlyFiles: removeReadOnlyFiles, onException, token: token )
                        .ConfigureAwait( false );
                }
            }
            catch ( DirectoryNotFoundException exception ) {
                Log( exception );
            }
            catch ( SecurityException exception ) {
                Log( exception );
            }
            catch ( UnauthorizedAccessException exception ) {
                Log( exception );
            }
            catch ( IOException exception ) {
                Log( exception );
            }
        }

        void RemoveFolderIfEmpty() {
            try {
                if ( !deleteEmptyFolders || folder.EnumerateDirectories().Any() || folder.EnumerateFiles().Any() ) {
                    return;
                }

                folder.Delete();
            }
            catch ( FileNotFoundException exception ) {
                Log( exception );
            }
            catch ( DirectoryNotFoundException exception ) {
                Log( exception );
            }
            catch ( SecurityException exception ) {
                Log( exception );
            }
            catch ( UnauthorizedAccessException exception ) {
                Log( exception );
            }
            catch ( IOException exception ) {
                Log( exception );
            }
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 C#删除一个文件夹以及该文件夹内的所有文件和文件夹 - C# delete a folder and all files and folders within that folder Rackspace CloudFiles C#API:如何在根“文件夹”中列出文件,以及如何在“文件夹”中列出(子)文件夹? - Rackspace CloudFiles C# API: How to list files on root 'folder', and how to list (sub)folders within a 'folder'? 如何使用 C# 从包含大量其他文件或文件夹的文件夹中正确删除 .Net Core 中的文件 - How to properly delete a file in .Net Core with C# from a folder with large amount of other files or folders 尝试删除文件夹中的所有文件,在c#中删除2个选定的文件 - Trying to delete all files in a folder exept 2 selected files in c# 删除文件但不删除文件夹C# - Delete files but not folder C# 将文件删除到文件夹 c# - Delete files into a folder c# C#控制台应用程序删除文件和文件夹 - C# console Application delete files and folders 如何使用 C# 从 windows Temp 文件夹中删除所有文件? (当进程运行时) - How do you delete all files from the windows Temp folder using C#? (When the processes are running) 如何列出硬盘驱动器上的所有文件和文件夹? - c# - How to list all files and folders on a hard drive? 如何使用 UWP C# 备份 USB 中的所有文件夹和文件? - How to Backup all the folders and files in a USB using UWP C#?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM