C# 将文件发送到RecyleBin,大文件将被永久删除

C# 将文件发送到RecyleBin,大文件将被永久删除,c#,.net,C#,.net,好的,有两种方法可以将文件发送到.net中的Recyle Bin,使用Microsoft.VisualBasic.FileIO.FileSystem.DeleteFile或使用SHFileOperation。这两种方法都很好,但如果文件无法放入回收站,它们会永久删除该文件。 若文件太大或只是不删除它,它是否可能抛出异常或返回布尔值?(不需要默认的确认对话框) 我得到的一种方法是获得卷允许的最大回收站大小,然后减去使用的大小,检查文件是否会被发送到RB或永久删除,但如果删除许多文件并反复检查,可能

好的,有两种方法可以将文件发送到.net中的Recyle Bin,使用
Microsoft.VisualBasic.FileIO.FileSystem.DeleteFile
或使用
SHFileOperation
。这两种方法都很好,但如果文件无法放入回收站,它们会永久删除该文件。 若文件太大或只是不删除它,它是否可能抛出异常或返回布尔值?(不需要默认的确认对话框)

我得到的一种方法是获得卷允许的最大回收站大小,然后减去使用的大小,检查文件是否会被发送到RB或永久删除,但如果删除许多文件并反复检查,可能会变得很糟糕


还有什么我可以尝试的吗?

我从你的帖子中可以得到的信息是,你想删除文件,但如果文件太大而无法发送到回收站,就不想删除它们。您的目标有点不清楚,但似乎您担心在批量删除时检查每个文件的回收站

考虑到这一点,如果要批量删除文件,其中一些文件可以进入回收站,而另一些文件不能,但您希望用户能够恢复这些文件,那么集中的哪些文件可以进入回收站,哪些文件不能

您可以收集所有文件的大小,然后对照回收站进行检查。如果太大,不要删除其中任何一个(或给出永久删除提示)


除非您试图重新制作文件资源管理器,否则我建议您在应用程序中使用一个垃圾文件夹,这样您可以获得更多的控制权

这个问题不像我一开始想的那么简单。然而,我发现它仍然有可能被解决

首先,你需要知道回收站的使用量。Win32的SHQueryRecycleBin可以为您做到这一点:

/// <summary>
/// Retrieves the size of the Recycle Bin and the number of items in it, of a specific drive
/// </summary>
/// <param name="pszRootPath">The path of the root drive on which the Recycle Bin is located</param>
/// <param name="pSHQueryRBInfo">A SHQUERYRBINFO structure that receives the Recycle Bin information</param>
/// <returns></returns>
[DllImport("shell32.dll")]
static extern int SHQueryRecycleBin(string pszRootPath, ref SHQUERYRBINFO pSHQueryRBInfo);

/// <summary>
/// Contains the size and item count information retrieved by the SHQueryRecycleBin function
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct SHQUERYRBINFO
{
    /// <summary>
    /// The size of the structure, in bytes
    /// </summary>
    public int cbSize;
    /// <summary>
    /// The total size of all the objects in the specified Recycle Bin, in bytes
    /// </summary>
    public long i64Size;
    /// <summary>
    /// The total number of items in the specified Recycle Bin
    /// </summary>
    public long i64NumItems;
}
其次,(至少在Win7上)用户可以确定(几乎)每个驱动器上为回收站保留的大小。因此,您需要知道我们可以获得的每个驱动器的回收站的最大容量。此信息可在注册表中找到。但我们还需要检索所有驱动器的GUID:

/// <summary>
/// Get from the registry all the drive guids
/// </summary>
static string[] GetDriveIds()
{
    const string registryPath = @"Software\Microsoft\Windows\CurrentVersion\Explorer\BitBucket\Volume\";
    RegistryKey reg = Registry.CurrentUser.OpenSubKey(registryPath);
    string[] readIn = reg.GetSubKeyNames();
    string[] driveIds = new string[readIn.Length - 1];
    Array.Copy(readIn, 1, driveIds, 0, readIn.Length - 1); // The first item must be removed
    return driveIds;
}

/// <summary>
/// Get and return the drive's recycle bin's MaxCapacity
/// </summary>
/// <param name="driveId">The guid of the specified drive</param>
/// <returns>The size in mega bytes</returns>
static int FindDriveCapacity(string driveId)
{
    const string registryPath = @"Software\Microsoft\Windows\CurrentVersion\Explorer\BitBucket\Volume\{0}\";
    RegistryKey reg = Registry.CurrentUser.OpenSubKey(
        string.Format(registryPath, driveId));
    return (int)reg.GetValue("MaxCapacity", 0);
}
我们必须做的最后一件事是用驱动器号映射guid。我们仍然需要使用注册表:

/// <summary>
/// Map the drive letter mapped by the drive ID
/// </summary>
/// <param name="driveId">The guid of the drive</param>
static string MapDriveLetter(string driveId)
{
    const string registryPath = @"SYSTEM\MountedDevices";
    RegistryKey reg = Registry.LocalMachine.OpenSubKey(registryPath);
    string[] readIn = reg.GetValueNames();
    byte[] keyCode = {};
    Regex regGuid = new Regex(@"\{[^\}]+\}");
    Regex regDriveLetter = new Regex(@"[A-Z]:$");
    foreach (string keyRead in readIn) {
        if (regGuid.IsMatch(keyRead) && regGuid.Match(keyRead).Value == driveId )
            keyCode = (byte[])reg.GetValue(keyRead, null);                
    }
    foreach (string keyRead in readIn)
    {
        byte[] codeRead = (byte[])reg.GetValue(keyRead, null);
        if (!regGuid.IsMatch(keyRead) && keyCode.SequenceEqual(codeRead))
        {
            if (regDriveLetter.IsMatch(keyRead)) // Get the drive letter in the form "E:"
                return regDriveLetter.Match(keyRead).Value;
        }
    }
    return string.Empty;
}

将所有信息结合在一起,您应该能够在哪个驱动器上知道系统可能永久删除一个或多个文件的大小。

不要删除该文件,而是使用不同的路径ie app_history文件夹重命名该文件。重命名方法有两个要点

您可以重命名文件的路径部分,如果路径位于同一磁盘驱动器上,则重命名运行得非常快,因为只有指向磁盘上文件的指针发生了更改。如果路径指向其他驱动器,则文件将被移动。这一切都是在windows操作系统中自动发生的

程序在物理上无法删除文件,因此它永远不会因为删除不可恢复的文件而受到不良影响


请记住,在windows中重命名可以更改文件的路径。

是否需要反复检查?您能否获得最大大小并减去已使用的大小,然后继续减去正在回收的文件的大小?可以,但也可能是其他应用程序正在删除或用户手动删除文件(发送到RB)。删除文件夹会变得更复杂。如果你想保证文件不会丢失,听起来回收站是发送文件的错误地方。回收站周围的策略由用户(及其管理员)决定,而不是由您的程序决定。想象一下,您的程序已经成功地实现了您正在寻找的“回收站或不删除”功能。此代码运行并报告成功传输到回收站后,用户立即决定(可能他们很无聊)去清空他们的回收站。最终的结果是你认为你已经成功了,但文件仍然没有了(就像过去一样)@Damien_the_unsiver,这正是我想要的。我想像windows资源管理器一样将文件发送到RB。所以用户可以在错误删除时恢复。他们可以随时清空回收站。与资源管理器完全相同。获取总文件大小也可能失败。假设这样,1000个文件需要放入回收站,程序得到了总大小,可以放入RB,但同时explorer或其他一些应用程序会将大文件发送到RB。现在,我的程序中的文件将永远不会到达回收站。是的,创建自己的垃圾箱文件夹是个好主意,但我无法实现它,我希望尽可能靠近windows资源管理器编写删除操作。:)+谢谢你的回答:)我找到了这个:。我会在我的电脑上测试这个,但是,如果我从windows资源管理器中删除这个文件,这个文件对于windows永久删除的回收站来说太大了。毫无疑问。。。。strange@bdn02:右键单击回收站>属性。并为卷选择自定义大小。感谢+1。不幸的是,对于explorer来说也是如此。我不相信有办法锁定RB。在删除过程中,总有可能有人将某物移动到回收站。您可以尝试删除,如果您的文件由于删除过程中有人将其最大化而失败,请回滚您的删除,然后使用永久删除对话框继续。我相信explorer只是移动到RB,直到遇到问题,然后对话。确切地说,我确实做了类似的事情。获取这些信息从来都不是问题,问题是即使使用它,文件仍然可以被永久删除。例如,当删除许多文件时,您将获得总大小并检查是否适合RB。但是,当您删除多个文件(不同路径,而不是子目录)时,如果其他应用程序(如windows资源管理器)也将文件发送到RB,并且文件足够大,无法容纳我们的文件,该怎么办。然后我们其余的删除文件将被永久删除。这就是为什么我问我是否可以试试别的东西。不管怎样,谢谢你:)+1你不能这样做
string[] driveIds = GetDriveIds();
int driveNo = 0;
foreach (string driveId in driveIds)
{
    Console.WriteLine("{0}. MaxCapacity of drive {1} is {2:#,##0} bytes",
        ++driveNo, driveId, FindDriveCapacity(driveId));
}
/// <summary>
/// Map the drive letter mapped by the drive ID
/// </summary>
/// <param name="driveId">The guid of the drive</param>
static string MapDriveLetter(string driveId)
{
    const string registryPath = @"SYSTEM\MountedDevices";
    RegistryKey reg = Registry.LocalMachine.OpenSubKey(registryPath);
    string[] readIn = reg.GetValueNames();
    byte[] keyCode = {};
    Regex regGuid = new Regex(@"\{[^\}]+\}");
    Regex regDriveLetter = new Regex(@"[A-Z]:$");
    foreach (string keyRead in readIn) {
        if (regGuid.IsMatch(keyRead) && regGuid.Match(keyRead).Value == driveId )
            keyCode = (byte[])reg.GetValue(keyRead, null);                
    }
    foreach (string keyRead in readIn)
    {
        byte[] codeRead = (byte[])reg.GetValue(keyRead, null);
        if (!regGuid.IsMatch(keyRead) && keyCode.SequenceEqual(codeRead))
        {
            if (regDriveLetter.IsMatch(keyRead)) // Get the drive letter in the form "E:"
                return regDriveLetter.Match(keyRead).Value;
        }
    }
    return string.Empty;
}
string code = MapDriveLetter("{f4b90148-66f6-11e3-9ac5-806e6f6e6963}");