簡體   English   中英

如何刪除所有文件/文件夾但將根文件夾保留在 C# 中

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

我寫了一些代碼來遞歸刪除 .Net 中的所有文件/文件夾,它可以工作,但我想保留根文件夾。 有沒有辦法修改文件夾刪除條件 (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);
        }
    }
}

稍微修改一下代碼。 添加一個新參數 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);
        }
    }
}

我不會亂用遞歸刪除。 並使用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); 
    }
}

您還可以依賴 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);
}

這應該首先刪除根目錄(spath)中的所有文件,然后遞歸刪除所有子目錄和內容。

這個例子應該像你描述的那樣工作。

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

我想看看它的異步版本是如何工作的。 干得好。

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM