以事务方式删除目录中的所有文件和文件夹

时间:2022-01-03 02:23:06

This is similar with this question but with one more requirement:

这与此问题类似,但还有一个要求:

Since the deletion of files can fail for whatever reasons. So I want the operation to be "transacted" which mean the whole operation either success in total, or fail and do not change anything at all.

由于删除文件可能因任何原因而失败。所以我希望操作“交易”,这意味着整个操作要么全部成功,要么失败并且根本不做任何改变。

In general this will be very very hard and I can't see any possibility to recover when the physical hard drive suddenly broken. So a weakened clause would be: if it success, we finished. Otherwise if fail, restore everything to the original state when possible.

一般来说,这将是非常非常困难的,当物理硬盘突然断裂时,我看不到任何恢复的可能性。所以一个弱化的条款是:如果成功,我们就完成了。否则,如果失败,请尽可能将所有内容恢复到原始状态。

Some kind of errors I could think of would be:

我能想到的某种错误是:

  1. Access violation. You simply don't allowed to delete some files or folders. This is the case that I wanted to handle the most.

    访问冲突。您根本不允许删除某些文件或文件夹。这是我想要处理最多的情况。

  2. File/folder was used by somebody else and so it is "locked". In Linux this is not a problem but in Windows it is. This is also to be handled.

    其他人使用文件/文件夹,因此它被“锁定”。在Linux中,这不是问题,但在Windows中它是。这也是要处理的。

  3. If it is a network folder there could be network issues. The recover can be hard or impossible. I would not expect this kind of error to be properly handled.

    如果是网络文件夹,则可能存在网络问题。恢复可能很难或不可能。我不希望这种错误得到妥善处理。

  4. Hardware failure. I don't think any recover can happen here.

    硬件故障。我认为这里不会发生任何恢复。

Scenario

You have a software that can export its internal data. The result is in a folder and with sub-folder names timestamped.

您有一个可以导出其内部数据的软件。结果是在一个文件夹中,并且子文件夹名称带有时间戳。

Now if the user specified a folder that is not empty (probably a previous output folder), the software will create new sub-folders on top of it, which is a mass. So you want to ensure the folder is empty before performing the export.

现在,如果用户指定了一个非空的文件夹(可能是以前的输出文件夹),软件将在其上创建新的子文件夹,这是一个质量。因此,您希望在执行导出之前确保文件夹为空。

You can easily detect the folder emptiness and alert the user if not. But if the user say "go ahead and do it" you should do something then. Now, what if you were deleted some of the files and failed on others?

如果没有,您可以轻松检测文件夹空白并提醒用户。但是,如果用户说“继续做”,那么你应该做点什么。现在,如果您删除了某些文件而其他文件失败了怎么办?

Going ahead in this case is just creating worse mass. At the same time the user would not expect a damaged folder without getting anything working. So it is better to either give them a fully working output or does not change the previous output at all.

在这种情况下继续前进只会造成更糟糕的质量。同时,如果没有任何工作,用户不会期望损坏的文件夹。因此,最好是给它们一个完全正常工作的输出,或者根本不改变以前的输出。

2 个解决方案

#1


As per comments, I'll give you the pseudocode for the process you can follow writing the code:

根据评论,我会给你编写代码的过程的伪代码:

Clear contents of cache folder if any files exist (they shouldn't)
Copy contents of destination folder to cache folder
Try
    While files exist, iterate
        Delete file
    End While
Catch
    While files exist in cache, iterate
        If file does not exist in destination folder
            Move file from cache to destination
        else
            Delete file from cache
        end If
    End While
End Try

#2


By following the guidelines given in the comments, I came up with this solution.

按照评论中给出的指导原则,我提出了这个解决方案。

The following code will attempt to move everything to a temporary folder inside the given folder. If success, it returns True. If failed, the catch block will then try to move everything back and return a False. In either case, the finally block will remove the temporary folder recursively.

以下代码将尝试将所有内容移动到给定文件夹中的临时文件夹。如果成功,则返回True。如果失败,catch块将尝试将所有内容移回并返回False。在任何一种情况下,finally块将递归删除临时文件夹。

public static bool EmptyFolderTransactionaly(string folder)
{
    var directoryInfo = new DirectoryInfo(folder);
    var tmpDir = Directory.CreateDirectory(Path.Combine(folder, Path.GetFileName(Path.GetTempFileName())));
    try
    {
        foreach (var e in directoryInfo.EnumerateFiles())
        {
            e.MoveTo(Path.Combine(tmpDir.FullName, e.Name));
        }
        foreach (var e in directoryInfo.EnumerateDirectories().Where(e => e.Name!=tmpDir.Name))
        {
            e.MoveTo(Path.Combine(tmpDir.FullName, e.Name));
        }
        return true;
    }
    catch
    {
        foreach (var e in tmpDir.EnumerateDirectories())
        {
            e.MoveTo(Path.Combine(directoryInfo.FullName, e.Name));
        }
        foreach (var e in tmpDir.EnumerateFiles())
        {
            e.MoveTo(Path.Combine(directoryInfo.FullName, e.Name));
        }
        return false;
    }
    finally
    {
        tmpDir.Delete(true);
    }
}

Let me know if you see any risks in the code.

如果您发现代码中存在任何风险,请与我们联系。

#1


As per comments, I'll give you the pseudocode for the process you can follow writing the code:

根据评论,我会给你编写代码的过程的伪代码:

Clear contents of cache folder if any files exist (they shouldn't)
Copy contents of destination folder to cache folder
Try
    While files exist, iterate
        Delete file
    End While
Catch
    While files exist in cache, iterate
        If file does not exist in destination folder
            Move file from cache to destination
        else
            Delete file from cache
        end If
    End While
End Try

#2


By following the guidelines given in the comments, I came up with this solution.

按照评论中给出的指导原则,我提出了这个解决方案。

The following code will attempt to move everything to a temporary folder inside the given folder. If success, it returns True. If failed, the catch block will then try to move everything back and return a False. In either case, the finally block will remove the temporary folder recursively.

以下代码将尝试将所有内容移动到给定文件夹中的临时文件夹。如果成功,则返回True。如果失败,catch块将尝试将所有内容移回并返回False。在任何一种情况下,finally块将递归删除临时文件夹。

public static bool EmptyFolderTransactionaly(string folder)
{
    var directoryInfo = new DirectoryInfo(folder);
    var tmpDir = Directory.CreateDirectory(Path.Combine(folder, Path.GetFileName(Path.GetTempFileName())));
    try
    {
        foreach (var e in directoryInfo.EnumerateFiles())
        {
            e.MoveTo(Path.Combine(tmpDir.FullName, e.Name));
        }
        foreach (var e in directoryInfo.EnumerateDirectories().Where(e => e.Name!=tmpDir.Name))
        {
            e.MoveTo(Path.Combine(tmpDir.FullName, e.Name));
        }
        return true;
    }
    catch
    {
        foreach (var e in tmpDir.EnumerateDirectories())
        {
            e.MoveTo(Path.Combine(directoryInfo.FullName, e.Name));
        }
        foreach (var e in tmpDir.EnumerateFiles())
        {
            e.MoveTo(Path.Combine(directoryInfo.FullName, e.Name));
        }
        return false;
    }
    finally
    {
        tmpDir.Delete(true);
    }
}

Let me know if you see any risks in the code.

如果您发现代码中存在任何风险,请与我们联系。