Отправить файл в корзину


85

В настоящее время я использую следующую функцию

file.Delete();

Но как я могу использовать эту функцию для отправки файла в корзину вместо того, чтобы просто удалить его сразу?



3
Ссылка @UweKeim теперь мертва, вы можете найти версию журнала MSDN в формате .chm (декабрь 2007 г.) здесь , статья называется, .NET Matters: IFileOperation in Windows Vistaи она находится в Columnsпапке.
jrh 04

У меня статья не открывается в файле .chm. Эта ссылка работает: docs.microsoft.com/en-us/archive/msdn-magazine/2007/de December/…
RandomEngy

Также вам необходимо добавить FOFX_RECYCLEONDELETE = 0x00080000к операциям флаги, и этот флаг поддерживается только в Windows 8 или выше.
RandomEngy

Ответы:


54

ПРИМЕЧАНИЕ. Это также не работает с интерактивными приложениями без пользовательского интерфейса, такими как службы Windows.

Эта оболочка может предоставить вам необходимую функциональность:

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
Удалите Pack = 1 при компиляции для 64-битной платформы (иначе произойдет сбой). Если Pack = 1 не указан, это будет работать как для 32-битных, так и для 64-битных версий. pinvoke.net/default.aspx/Structures/SHFILEOPSTRUCT.html
Шон

1
При использовании Pack = 1 было выброшено исключение AccessViolationException. Удаление сделало свое дело. Кстати, 64-битная Windows
P1nGu1n

1
Какие требования даже для запуска этого кода? Я удаляю Pack = 1, но он все равно не компилируется. DllImport, DllImportAttribute, MarshalAs, MarshalAsAttribute, StructLayout, StructLayoutAttribute не существуют в качестве пространства имен. Любая помощь, пожалуйста, спасибо :)
puretppc

1
SHFileOperation не обрабатывает длинные пути и завершится ошибкой для путей длиннее MAX_PATH (даже с префиксом \\? \).
Melvyn

157

Используйте FileSystem.DeleteFile и укажите правильный RecycleOption .

Хотя это будет работать с интерактивными приложениями пользовательского интерфейса, это не будет работать с интерактивными приложениями без пользовательского интерфейса, такими как приложение службы Windows.


17
@noldorin Это прекрасное решение, не заслуживающее отрицательной оценки. Я хотел бы получить ссылку на то, почему доступ к библиотеке VisualBasic «уродлив».
jsmith

7
@noldorin: особенно в этом случае в Microsoft.VisualBasic.FileIO.FileSystemосновном то же самое, что и в примере, размещенном здесь, используя SHFileOperation.
Dirk Vollmar

19
@Noldorin: Уродливо, а? Для меня способ WinAPI намного уродливее - кроме того, у вас будет больше шансов что-то испортить. Мне лично не нравится синтаксис VB, но в сборках я просто ILне против. Кстати, сборка VB вызывает ту же функцию WinAPI.
Jaroslav Jandek

7
@Noldorin: Устарело? Вы Microsoft.VisualBasic.Compatibilityслучайно не приняли сборку ? Этого я бы избегал. Не похоже, что в ближайшее время он будет устаревшим (он используется в механизме отчетов RDL и т. Д.).
Jaroslav Jandek

6
@Noldorin: использование встроенной сборки фреймворка выглядит лучшим решением, чем жесткое сопоставление с shell32.dll. Используя сборки фреймворка, вы получаете переносимые изменения и более позднюю эволюцию. Сопоставляя системные библиотеки, вы
рискуете в

41

Из MSDN :

Добавьте ссылку на сборку Microsoft.VisualBasic. Нужный класс находится в этой библиотеке.

Добавьте этот оператор using в начало файла using Microsoft.VisualBasic.FileIO;

Используйте FileSystem.DeleteFileдля удаления файла, есть возможность указать корзину или нет.

Используйте FileSystem.DeleteDirectoryдля удаления каталога с возможностью указать, отправлять его в корзину или нет.


Проблема с включением Microsoct.VisualBasic заключается в том, что он конфликтует с тем, что я использую SearchOption в другом месте моей программы (часть функции GetFiles ()).
muttley91

8
@rar Downvote по-прежнему не заслуживает внимания, поскольку в вопросе не указано, что «на библиотеку VisualBasic нельзя ссылаться из-за конфликта». Что вы можете легко решить в своем коде. stackoverflow.com/questions/1317263/…
jsmith

1
Этот метод, по-видимому, внутренне использует SHFileOperation, который не обрабатывает длинные пути и завершится ошибкой с путями, превышающими MAX_PATH (даже с префиксом \\? \).
Melvyn

18

Следующее решение проще других:

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 Controls And Automation» (из меню COM), чтобы иметь возможность использовать Shell32пространство имен. Он будет динамически связан с вашим проектом, а не компилироваться вместе с вашей программой.

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


8
Ваш ответ будет лучше, если вы сосредоточитесь на своем решении вместо того, чтобы комментировать другие ответы в первом абзаце. Кроме того, для ясности я бы заменил 10на Shell32.ShellSpecialFolderConstants.ssfBITBUCKET. Возможно, стоит упомянуть второй параметр MoveHere, касающийся таких опций, как 64 («Сохранить информацию об отмене, если возможно»). Связывание некоторых источников документации из MSDN было бы неплохим завершением.
grek40

2
Похоже, что при вызове MoveHere не возникает никаких ошибок: вызов его для несуществующего файла завершается неудачно! Он также автоматически завершается ошибкой на путях длиннее MAX_CHARS, с префиксом «\\? \» Или без него ...
Мелвин

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
и двойной ноль завершают строку.
Sean E

1
SHFileOperation не обрабатывает длинные пути и завершится ошибкой для путей длиннее MAX_PATH (даже с префиксом \\? \).
Melvyn

Обратите внимание, что эта строка shf.pFrom = @"C:\test.txt";неверна - pFrom должен оканчиваться двойным нулем. Вы должны добавить \0в файл shf.pFrom = "C:\\text.txt\0";. См docs.microsoft.com/en-us/windows/desktop/api/shellapi/...
lindexi


1

Для этого есть встроенная библиотека .

Сначала добавьте ссылку Microsoft.VisualBasic Затем добавьте этот код:

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

Я нашел это здесь .


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

}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.