好的,有两种方法可以将文件发送到.net中的Recyle Bin,无论是使用Microsoft.VisualBasic.FileIO.FileSystem.DeleteFile还是使用SHFileOperation.两者都运行良好,但如果文件无法放入回收站内,它们会永久删除文件.如果文件太大或只是不删除它,它是否可能以某种方式抛出异常或返回布尔值?(不想要默认确认对话框)
我得到的一种方法是获取卷允许的最大回收站大小然后减去使用的大小并检查文件是否将发送到RB或永久删除,但如果删除许多文件并反复检查它可能会变坏.
还有什么我可以尝试的吗?
小智 5
这个问题并不像我一开始想象的那么简单。不过我发现还是可以解决的。
首先,您需要知道回收站的使用量。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;
}
Run Code Online (Sandbox Code Playgroud)
使用以下演示代码来检索此信息:
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);
Run Code Online (Sandbox Code Playgroud)
其次,(至少在 Win7 上)用户可以确定为(几乎)每个驱动器上的回收站保留多少大小。因此,您需要知道我们可以获得的每个驱动器的回收站的最大容量。该信息可以在注册表中找到。但我们还需要检索所有驱动器的指南:
/// <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);
}
Run Code Online (Sandbox Code Playgroud)
使用以下代码,您可以检索每个驱动器的最大容量:
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));
}
Run Code Online (Sandbox Code Playgroud)
我们要做的最后一件事是将 GUI 与驱动器号进行映射。我们仍然需要使用注册表:
/// <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;
}
Run Code Online (Sandbox Code Playgroud)
只需通过 guid 即可获取驱动器号:
string code = MapDriveLetter("{f4b90148-66f6-11e3-9ac5-806e6f6e6963}");
Run Code Online (Sandbox Code Playgroud)
将所有信息组合在一起,您应该能够知道哪个驱动器上的一个或多个文件的大小可能会被系统永久删除。
我从您的帖子中可以了解到,您想要删除文件,但如果文件太大而无法发送到回收站,则不想删除它们。您的目标有点不清楚,但似乎您担心在批量删除时检查每个文件的回收站。
考虑一下,如果您要批量删除,有些文件可以进入回收站,有些则不能,但您希望用户能够恢复这些文件,那么集合中的哪些文件会进入回收站bin 和哪个不是?
您可以收集所有文件的大小,然后根据回收站进行检查。如果太大,请勿删除其中任何一个(或给出永久删除提示)。
除非您尝试重新制作文件资源管理器,否则我建议您在应用程序中使用垃圾文件夹,这会给您更多的控制权。