c# - 发送文件到回收站,大文件永久删除

标签 c# .net

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

我得到的一种方法是获取该卷允许的最大回收站大小,然后减去已用大小并检查文件是否将发送到 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;
}

使用以下演示代码检索此信息:

const int S_OK = 0;
//string drivePath = @"C:\$RECYCLE.BIN\";
string drivePath = @"D:\$RECYCLE.BIN\";
SHQUERYRBINFO pSHQueryRBInfo = new SHQUERYRBINFO();
pSHQueryRBInfo.cbSize = Marshal.SizeOf(typeof(SHQUERYRBINFO));
int hresult = SHQueryRecycleBin(drivePath, ref pSHQueryRBInfo);
Console.WriteLine("{0} Drive {1} contains {2} item(s) in {3:#,##0} bytes", 
    hresult == S_OK ? "Success!" : "Fail!",
    drivePath, pSHQueryRBInfo.i64NumItems, pSHQueryRBInfo.i64Size);

其次,(至少在 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);
}

使用以下代码,您可以检索每个驱动器的最大容量:

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

我们要做的最后一件事是将 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;
}

只要传递guid就可以得到盘号:

string code = MapDriveLetter("{f4b90148-66f6-11e3-9ac5-806e6f6e6963}");

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

关于c# - 发送文件到回收站,大文件永久删除,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21406508/

相关文章:

c# - 将数据传递给 .net Web 服务并取回结果?

c# - MS Test 的测试覆盖率工具

c# - WPF标签下的可点击按钮

c# - 引用 OpenWebKitSharp 在 C# 中使用 WebKit

.net - 在 .NET Framework 中使用旧版 "Communication"类

c# - 如何将 .NET CommandArgument 用作非字符串对象?

c# - Parallel.ForEach 与 MatchCollection

c# - 如何在 ASP.Net 中将 word 转换为 pdf

c# - C# 扩展方法是否仅适用于实例方法?

c# - 如何禁止在 .NET 中将按键打印到控制台?