将文件发送到回收站


83

目前,我正在使用以下功能

file.Delete();

但是,如何使用此功能将文件发送到回收站,而不是直接将其删除?



3
@UweKeim的链接现在已死,您可以在这里找到MSDN Magazine的.chm格式版本(2007年12月),该文章被调用.NET Matters: IFileOperation in Windows Vista并且位于Columns文件夹中。
jrh

对于我来说,本文不在.chm文件中打开。此链接:docs.microsoft.com/en-us/archive/msdn-magazine/2007/december/...
RandomEngy

另外,您需要添加FOFX_RECYCLEONDELETE = 0x00080000操作标志,并且该标志仅在Windows 8或更高版本上受支持。
RandomEngy

Answers:


52

注意:这也不适用于非UI Interactive应用程序(例如Windows Services)

该包装器可以为您提供所需的功能:

using System.Runtime.InteropServices;

public class FileOperationAPIWrapper
    {
        /// <summary>
        /// Possible flags for the SHFileOperation method.
        /// </summary>
        [Flags]
        public enum FileOperationFlags : ushort
        {
            /// <summary>
            /// Do not show a dialog during the process
            /// </summary>
            FOF_SILENT = 0x0004,
            /// <summary>
            /// Do not ask the user to confirm selection
            /// </summary>
            FOF_NOCONFIRMATION = 0x0010,
            /// <summary>
            /// Delete the file to the recycle bin.  (Required flag to send a file to the bin
            /// </summary>
            FOF_ALLOWUNDO = 0x0040,
            /// <summary>
            /// Do not show the names of the files or folders that are being recycled.
            /// </summary>
            FOF_SIMPLEPROGRESS = 0x0100,
            /// <summary>
            /// Surpress errors, if any occur during the process.
            /// </summary>
            FOF_NOERRORUI = 0x0400,
            /// <summary>
            /// Warn if files are too big to fit in the recycle bin and will need
            /// to be deleted completely.
            /// </summary>
            FOF_WANTNUKEWARNING = 0x4000,
        }

        /// <summary>
        /// File Operation Function Type for SHFileOperation
        /// </summary>
        public enum FileOperationType : uint
        {
            /// <summary>
            /// Move the objects
            /// </summary>
            FO_MOVE = 0x0001,
            /// <summary>
            /// Copy the objects
            /// </summary>
            FO_COPY = 0x0002,
            /// <summary>
            /// Delete (or recycle) the objects
            /// </summary>
            FO_DELETE = 0x0003,
            /// <summary>
            /// Rename the object(s)
            /// </summary>
            FO_RENAME = 0x0004,
        }



        /// <summary>
        /// SHFILEOPSTRUCT for SHFileOperation from COM
        /// </summary>
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        private struct SHFILEOPSTRUCT
        {

            public IntPtr hwnd;
            [MarshalAs(UnmanagedType.U4)]
            public FileOperationType wFunc;
            public string pFrom;
            public string pTo;
            public FileOperationFlags fFlags;
            [MarshalAs(UnmanagedType.Bool)]
            public bool fAnyOperationsAborted;
            public IntPtr hNameMappings;
            public string lpszProgressTitle;
        }

        [DllImport("shell32.dll", CharSet = CharSet.Auto)]
        private static extern int SHFileOperation(ref SHFILEOPSTRUCT FileOp);

        /// <summary>
        /// Send file to recycle bin
        /// </summary>
        /// <param name="path">Location of directory or file to recycle</param>
        /// <param name="flags">FileOperationFlags to add in addition to FOF_ALLOWUNDO</param>
        public static bool Send(string path, FileOperationFlags flags)
        {
            try
            {
                var fs = new SHFILEOPSTRUCT
                                        {
                                            wFunc = FileOperationType.FO_DELETE,
                                            pFrom = path + '\0' + '\0',
                                            fFlags = FileOperationFlags.FOF_ALLOWUNDO | flags
                                        };
                SHFileOperation(ref fs);
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// Send file to recycle bin.  Display dialog, display warning if files are too big to fit (FOF_WANTNUKEWARNING)
        /// </summary>
        /// <param name="path">Location of directory or file to recycle</param>
        public static bool Send(string path)
        {
            return Send(path, FileOperationFlags.FOF_NOCONFIRMATION | FileOperationFlags.FOF_WANTNUKEWARNING);
        }

        /// <summary>
        /// Send file silently to recycle bin.  Surpress dialog, surpress errors, delete if too large.
        /// </summary>
        /// <param name="path">Location of directory or file to recycle</param>
        public static bool MoveToRecycleBin(string path)
        {
            return Send(path, FileOperationFlags.FOF_NOCONFIRMATION | FileOperationFlags.FOF_NOERRORUI | FileOperationFlags.FOF_SILENT);

        }

        private static bool deleteFile(string path, FileOperationFlags flags)
        {
            try
            {
                var fs = new SHFILEOPSTRUCT
                                        {
                                            wFunc = FileOperationType.FO_DELETE,
                                            pFrom = path + '\0' + '\0',
                                            fFlags = flags
                                        };
                SHFileOperation(ref fs);
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        public static bool DeleteCompletelySilent(string path)
        {
            return deleteFile(path,
                              FileOperationFlags.FOF_NOCONFIRMATION | FileOperationFlags.FOF_NOERRORUI |
                              FileOperationFlags.FOF_SILENT);
        }
    }

我不知道该如何使用...您能解释一下吗?
muttley91

4
如果针对64位平台进行编译,请删除Pack = 1(否则将失败)。如果未指定Pack = 1,则它将同时适用于32位和64位。pinvoke.net/default.aspx/Structures/SHFILEOPSTRUCT.html
肖恩

1
使用Pack = 1时,将引发AccessViolationException。删除它就可以了。顺便说一下64位Windows
P1nGu1n 2013年

1
甚至运行此代码有什么要求?我删除了Pack = 1,但仍然无法编译。DllImport,DllImportAttribute,MarshalAs,MarshalAsAttribute,StructLayout,StructLayoutAttribute不作为命名空间存在。任何帮助,请谢谢:)
puretppc 2014年

1
SHFileOperation无法处理长路径,并且路径长度超过MAX_PATH(即使带有\\?\前缀)也会失败。
Melvyn

155

使用FileSystem.DeleteFile并指定正确的RecycleOption

尽管这将与UI Interactive Apps一起使用,但不适用于Windows Service应用程序等非UI交互式应用程序。


17
@noldorin这是一个非常好的解决方案,不应该被否决。我想了解为什么访问VisualBasic库是“丑陋的”。
jsmith

7
@noldorin:特别是在这种情况下Microsoft.VisualBasic.FileIO.FileSystem,与使用此处发布的示例基本相同SHFileOperation
德克·沃尔玛

18
@Noldorin:丑陋,是吗?对我来说,WinAPI的方式更丑陋-而且,您最好将某些东西弄乱。我个人不喜欢VB语法,但是在汇编中只是IL这样,所以我不介意。VB程序集调用相同的WinAPI函数btw。
Jaroslav Jandek'7

7
@Noldorin:过时了吗?你是不是Microsoft.VisualBasic.Compatibility偶然把大会弄错了?我避免的那个。似乎它不会很快被弃用(它已在RDL报告引擎中使用,等等)。
Jaroslav Jandek,2010年

6
@Noldorin:与使用硬式映射到shell32.dll相比,使用内置框架程序集似乎是一个更好的解决方案。使用框架程序集,您可以轻松地进行更改并获得后续的发展。映射到系统库后,您随时都有可能过时……
fredlegrain 2013年

41

MSDN

添加对Microsoft.VisualBasic程序集的引用。所需的类在此库中找到。

将此using语句添加到文件的顶部using Microsoft.VisualBasic.FileIO;

使用FileSystem.DeleteFile删除一个文件,它指定回收站与否的选项。

使用FileSystem.DeleteDirectory删除目录的选项来指定其发送到回收站与否。


包含Microsoct.VisualBasic的问题是,它与我在程序的其他位置(GetFiles()函数的一部分)对SearchOption的使用发生冲突。
muttley91

8
@rar Downvote仍然不值得,因为在“由于冲突而无法引用VisualBasic库”的问题中未指定它。您可以在代码中轻松解决该问题。stackoverflow.com/questions/1317263/…–
jsmith

1
此方法似乎在内部使用SHFileOperation,它不处理长路径,并且路径长于MAX_PATH(即使带有\\?\前缀)也会失败。
Melvyn

17

以下解决方案比其他解决方案更简单:

using Shell32;

static class Program
{
    public static Shell shell = new Shell();
    public static Folder RecyclingBin = shell.NameSpace(10);

    static void Main()
    {
        RecyclingBin.MoveHere("PATH TO FILE/FOLDER")
    }
}

您可以使用此库使用回收站的其他功能。

首先,不要忘记添加库“ Microsoft Shell控件和自动化”(从COM菜单),以便能够使用Shell32命名空间。它会动态链接到您的项目,而不是与您的程序一起编译。

[1]:https://i.stack.imgur.com/erV


8
当您专注于解决方案而不是在第一段中评论其他答案时,您的答案会更好。另外,为清楚起见,我将替换10Shell32.ShellSpecialFolderConstants.ssfBITBUCKET。值得提及的第二个参数是MoveHere关于64之类的选项(“如果可能,保留撤消信息”)。从MSDN链接一些文档源将是一个不错的结局。
grek40 '17

2
看起来对MoveHere的调用不会出现任何错误:在不存在的文件上调用它会失败,并且会以静默方式失败!在长度超过MAX_CHARS的路径上,无论是否带有“ \\?\”前缀,它也都会静默失败...
Melvyn

13

不幸的是,您需要诉诸Win32 API才能将文件删除到回收站中。根据这篇文章尝试以下代码。它利用通用SHFileOperation功能通过Windows Shell对文件系统进行操作。

定义以下内容(在实用程序类中最好)。

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto, Pack=1)]
public struct SHFILEOPSTRUCT
{
        public IntPtr hwnd;
        [MarshalAs(UnmanagedType.U4)] public int wFunc;
        public string pFrom;
        public string pTo;
        public short fFlags;
        [MarshalAs(UnmanagedType.Bool)] public bool fAnyOperationsAborted;
        public IntPtr hNameMappings;
        public string lpszProgressTitle;
}

[DllImport("shell32.dll", CharSet=CharSet.Auto)]
public static extern int SHFileOperation(ref SHFILEOPSTRUCT FileOp);

public const int FO_DELETE = 3;
public const int FOF_ALLOWUNDO = 0x40;
public const int FOF_NOCONFIRMATION = 0x10; // Don't prompt the user

并使用它删除文件并将其发送到回收站,您需要以下内容:

var shf = new SHFILEOPSTRUCT();
shf.wFunc = FO_DELETE;
shf.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION;
shf.pFrom = @"C:\test.txt";
SHFileOperation(ref shf);

1
和double null终止字符串。
肖恩e

1
SHFileOperation无法处理长路径,并且路径长度超过MAX_PATH(即使带有\\?\\前缀)也会失败。
Melvyn

请注意,此行shf.pFrom = @"C:\test.txt";是错误的-pFrom必须以double null终止。您应该添加\0文件shf.pFrom = "C:\\text.txt\0";。请参阅docs.microsoft.com/zh-CN/windows/desktop/api/shellapi/…–
lindexi,


1

我使用这种扩展方法,然后可以使用DirectoryInfo或FileInfo并将其删除。

public static class NativeMethods
{
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        struct SHFILEOPSTRUCT
    {
        public IntPtr hwnd;
        [MarshalAs(UnmanagedType.U4)]
        public int wFunc;
        public string pFrom;
        public string pTo;
        public short fFlags;
        [MarshalAs(UnmanagedType.Bool)]
        public bool fAnyOperationsAborted;
        public IntPtr hNameMappings;
        public string lpszProgressTitle;
    }
    private const int FO_DELETE = 0x0003;
    private const int FOF_ALLOWUNDO = 0x0040;           // Preserve undo information, if possible. 
    private const int FOF_NOCONFIRMATION = 0x0010;      // Show no confirmation dialog box to the user      


    [DllImport("shell32.dll", CharSet = CharSet.Auto)]
    static extern int SHFileOperation(ref SHFILEOPSTRUCT FileOp);

    static bool DeleteFileOrFolder(string path)
    {


        SHFILEOPSTRUCT fileop = new SHFILEOPSTRUCT();
        fileop.wFunc = FO_DELETE;
        fileop.pFrom = path + '\0' + '\0';            
        fileop.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION;


        var rc= SHFileOperation(ref fileop);
        return rc==0;
    }

    public static bool ToRecycleBin(this DirectoryInfo dir)
    {
        dir?.Refresh();
        if(dir is null || !dir.Exists)
        {
            return false;
        }
        else
            return DeleteFileOrFolder(dir.FullName);
    }
    public static bool ToRecycleBin(this FileInfo file)
    {
        file?.Refresh();

        if(file is null ||!file.Exists)
        {
            return false;
        }
        return DeleteFileOrFolder(file.FullName);
    }
}

如何调用它的示例可能是这样的:

private void BtnDelete_Click(object sender, EventArgs e)
{
    if(MessageBox.Show("Are you sure you would like to delete this directory?", "Delete & Close", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
        return;

    var dir= new DirectoryInfo(directoryName);
    dir.ToRecycleBin();

}

-1

内置的库

首先添加参考Microsoft.VisualBasic, 然后添加以下代码:

FileSystem.DeleteFile(path_of_the_file,
                        Microsoft.VisualBasic.FileIO.UIOption.AllDialogs,
                        Microsoft.VisualBasic.FileIO.RecycleOption.SendToRecycleBin,
                        Microsoft.VisualBasic.FileIO.UICancelOption.ThrowException);

在这里找到

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.