2

これを正しく行っているのか、それとも私のロジックが正しいのかはわかりません。

フォルダー構造を下って、特定の日数より古いファイルを削除しようとしています。この部分は正しく実装し、空のフォルダーを削除します。

これらすべてを 1 つのループで実行できますか?
フォルダの削除はどこで行うのですか?

3~4階層下までの空のフォルダを削除したい。

    private static void TraverseTree(System.IO.DirectoryInfo folder, double days)
    {
        Stack<string> dirs = new Stack<string>();

        if (!folder.Exists)
            throw new ArgumentException();

        dirs.Push(folder.FullName);

        while (dirs.Count > 0)
        {
            string currentDir = dirs.Pop();
            string[] subDirs;
            try
            {
                subDirs = System.IO.Directory.GetDirectories(currentDir);
            }
            // An UnauthorizedAccessException exception will be thrown if we do not have
            // discovery permission on a folder or file. It may or may not be acceptable 
            // to ignore the exception and continue enumerating the remaining files and 
            // folders. It is also possible (but unlikely) that a DirectoryNotFound exception 
            // will be raised. This will happen if currentDir has been deleted by
            // another application or thread after our call to Directory.Exists. The 
            // choice of which exceptions to catch depends entirely on the specific task 
            // you are intending to perform and also on how much you know with certainty 
            // about the systems on which this code will run.
            catch (UnauthorizedAccessException e)
            {
                Console.WriteLine(e.Message);
                continue;
            }
            catch (System.IO.DirectoryNotFoundException e)
            {
                Console.WriteLine(e.Message);
                continue;
            }

            string[] files = null;
            try
            {
                files = System.IO.Directory.GetFiles(currentDir);
            }
            catch (UnauthorizedAccessException e)
            {

                Console.WriteLine(e.Message);
                continue;
            }
            catch (System.IO.DirectoryNotFoundException e)
            {
                Console.WriteLine(e.Message);
                continue;
            }

            // Perform the required action on each file here.
            // Modify this block to perform your required task.
            foreach (string file in files)
            {
                try
                {
                    // Perform whatever action is required in your scenario.
                    System.IO.FileInfo fi = new System.IO.FileInfo(file);
                    Console.WriteLine("{0}: {1}, {2}", fi.Name, fi.Length, fi.CreationTime);

                    // Delete old files
                    if (fi.LastWriteTime < DateTime.Now.AddDays(-days))
                        fi.Delete();
                }
                catch (System.IO.FileNotFoundException e)
                {
                    // If file was deleted by a separate application
                    //  or thread since the call to TraverseTree()
                    // then just continue.
                    Console.WriteLine(e.Message);
                    continue;
                }
            }

            // Push the subdirectories onto the stack for traversal.
            // This could also be done before handing the files.
            foreach (string str in subDirs)
                dirs.Push(str);
        }
    }

コードはMSDNからのものです。

4

5 に答える 5

5

再帰的なアプローチは、おそらくよりクリーンになります。

private static void DeleteOldFilesAndFolders(string path)
{
    foreach (string directory in System.IO.Directory.GetDirectories(path))
    {
        DeleteOldFilesAndFolders(directory);

        // If the directory is empty and old, delete it here.
    }

    foreach (string file in System.IO.Directory.GetFiles(path))
    {
        // Check the file's age and delete it if it's old.
    }
}
于 2009-09-02T19:27:55.057 に答える
3

あなたのコードについて私が気づいたことは、ツリー構造をたどる数十行の「メカニズム」が、実際に作業を行う 2 行のコードを完全に圧倒していることです。これにより、このコードの読み取り、理解、変更、デバッグ、保守が困難になります。

代わりに私がすることは次のとおりです。

プログラムには、(1) すべてのファイルを取得する、(2) 削除するファイルを見つけるためにフィルター処理する、(3) 各ファイルを削除する、3 つの高レベルの操作しかありません。したがって、これらのそれぞれを 1 つのステートメントで実行するプログラムを作成します。

最初の操作では、上記のメカニズムを独自の関数に分解します。たとえば、IEnumerable を実装する関数で、ファイルに関する情報を生成し続けるだけです。それらに対しては何もしません。その唯一の目的は、ファイル情報を吐き出し続けることです。

そのメカニズムができたら、そのシーケンスの上にクエリを書き始めて、2 番目の操作を実行できます。3 番目の操作は、2 番目の操作の直後に続きます。

つまり、プログラムのメインラインは次のようになります。

var allFiles = TraverseFolder(folder);
var filesToDelete = from file in allFiles where IsOld(file) select file;
foreach(var fileToDelete in filesToDelete) Delete(fileToDelete);

それは明らかですか?

于 2009-09-02T19:47:50.290 に答える
0

ここにほぼ同じ質問があります:

ディレクトリ内のすべてのファイルとフォルダを削除するには?

これは名前による削除ですが、他のプロパティを確認できます。

于 2009-09-02T19:27:24.467 に答える
0

不足しているコード、エラー処理、およびチェックを実装して、ジョンのソリューションを強化しました。

/* Given a directory path and a datetime,
 * recursively delete all files and directories contained in such directory
 * (given directory included) that are younger than the given date.
 */
private bool DeleteDirectoryTree(string dir, DateTime keepFilesYoungerThan)
{
    //checks
    if (String.IsNullOrEmpty(dir) || !Directory.Exists(dir))
        return false;

    //recurse on children directories
    foreach (string childDir in Directory.GetDirectories(dir))
        DeleteDirectoryTree(childDir, keepFilesYoungerThan);

    //loop on children files
    foreach (string file in Directory.GetFiles(dir))
    {
        //calculate file datetime
        DateTime fileDT = new DateTime(Math.Max(File.GetCreationTime(file).Ticks, File.GetLastWriteTime(file).Ticks));
        //if file is old, delete it
        if (fileDT <= keepFilesYoungerThan)
            try
            {
                File.Delete(file);
                Log("Deleted file " + file);
            }
            catch (Exception e)
            {
                LogError("Could not delete file " + file + ", cause: " + e.Message);
            }
    }

    //if this directory is empty, delete it
    if (!Directory.EnumerateFileSystemEntries(dir).Any())
        try
        {
            Directory.Delete(dir);
            Log("Deleted directory " + dir);
        }
        catch (Exception e)
        {
            LogError("Could not delete directory " + dir + ", cause: " + e.Message);
        }

    return true;
}
于 2014-03-12T09:34:33.477 に答える
0

これは、IEnumerable として非再帰的に実装されたファイル システム ウォーカーを提供する、問題に対するより一般的な解決策です。

あなたのソリューションはおそらく次のように実装できます。

List<string> directoriesToDelete = new List<string>();
DirectoryWalker walker = new DirectoryWalker(@"C:\pathToSource\src",
    dir => {
        if (Directory.GetFileSystemEntries(dir).Length == 0) {
            directoriesToDelete.Add(dir);
            return false;
        }
        return true;
    },
    file => {
        if (FileIsTooOld(file)) {
            return true;
        }
        return false;
    }
    );
foreach (string file in walker)
    File.Delete(file);
foreach (string dir in directoriesToDelete)
    Directory.Delete(dir);
于 2009-09-02T19:47:29.807 に答える