简体   繁体   中英

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. 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?

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.

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.

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:

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM