Wyślij plik do Kosza

85

Obecnie używam następującej funkcji

file.Delete();

Ale jak mogę użyć tej funkcji, aby wysłać plik do kosza zamiast po prostu go usunąć?

muttley91
źródło
3
Łącze @ UweKeim jest teraz martwe, możesz znaleźć wersję MSDN Magazine (grudzień 2007) w formacie .chm tutaj , artykuł nazywa się .NET Matters: IFileOperation in Windows Vistai znajduje się w Columnsfolderze.
jrh
Artykuł nie otwiera się w pliku .chm. To łącze działa: docs.microsoft.com/en-us/archive/msdn-magazine/2007/december/…
RandomEngy
Musisz także dodać FOFX_RECYCLEONDELETE = 0x00080000flagi operacji, a ta flaga jest obsługiwana tylko w systemie Windows 8 lub nowszym.
RandomEngy

Odpowiedzi:

54

UWAGA: Nie działa to również w przypadku aplikacji interaktywnych innych niż UI, takich jak usługi Windows

To opakowanie może zapewnić potrzebną funkcjonalność:

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);
        }
    }
Eugene Cheverda
źródło
Nie rozumiem, jak tego używać ... czy możesz wyjaśnić?
muttley91
4
Usuń Pack = 1, jeśli kompilujesz dla platformy 64-bitowej (w przeciwnym razie nie powiedzie się). Bez opcji Pack = 1 będzie działać zarówno dla wersji 32-bitowej, jak i 64-bitowej. pinvoke.net/default.aspx/Structures/SHFILEOPSTRUCT.html
Sean
1
W przypadku używania Pack = 1 został zgłoszony wyjątek AccessViolationException. Usunięcie go załatwiło sprawę.
Nawiasem mówiąc,
1
Jakie są wymagania, aby w ogóle uruchomić ten kod? Usuwam Pack = 1, ale nadal się nie kompiluje. DllImport, DllImportAttribute, MarshalAs, MarshalAsAttribute, StructLayout, StructLayoutAttribute nie istnieją jako przestrzeń nazw. Jakakolwiek pomoc, dziękuję :)
puretppc
1
SHFileOperation nie obsługuje długich ścieżek i zakończy się niepowodzeniem w przypadku ścieżek dłuższych niż MAX_PATH (nawet z prefiksem \\? \).
Melvyn
157

Użyj FileSystem.DeleteFile i określ odpowiednią RecycleOption .

Chociaż będzie to działać z aplikacjami interaktywnymi UI, nie będzie działać z aplikacjami interaktywnymi bez interfejsu użytkownika, takimi jak aplikacja usługi Windows.

NG.
źródło
18
@noldorin To doskonałe rozwiązanie, które nie zasługuje na negatywną opinię. Chciałbym się dowiedzieć, dlaczego dostęp do biblioteki VisualBasic jest „brzydki”.
jsmith
7
@noldorin: Szczególnie w tym przypadku Microsoft.VisualBasic.FileIO.FileSystemrobi to w zasadzie to samo, co w przykładzie zamieszczonym tutaj przy użyciu SHFileOperation.
Dirk Vollmar
20
@Noldorin: Brzydki, co? Dla mnie sposób WinAPI jest o wiele brzydszy - lepiej też spróbuj coś zepsuć. Osobiście nie lubię składni VB, ale w zespołach jest ILtak po prostu, więc nie mam nic przeciwko. Zestaw VB btw wywołuje tę samą funkcję WinAPI.
Jaroslav Jandek
7
@Noldorin: Przestarzałe? Czy pomyliłeś montaż Microsoft.VisualBasic.Compatibilityprzez przypadek? Tego bym unikał. Nie wygląda na to, że wkrótce zostanie wycofany (jest używany w silniku raportowania RDL itp.).
Jaroslav Jandek
7
@Noldorin: Korzystanie z wbudowanego zestawu struktury wygląda na lepsze rozwiązanie niż przejście na sztywne mapowanie do shell32.dll. Korzystając z zestawów frameworka, otrzymujesz zmianę jako przenośną i późniejszą ewolucję. Mapując do bibliotek systemowych, każdego dnia możesz być przestarzały ...
fredlegrain
41

Z MSDN :

Dodaj odwołanie do zestawu Microsoft.VisualBasic. Potrzebna klasa znajduje się w tej bibliotece.

Dodaj tę instrukcję using na początku pliku using Microsoft.VisualBasic.FileIO;

Służy FileSystem.DeleteFiledo usuwania pliku, ma możliwość określenia kosza lub nie.

Służy FileSystem.DeleteDirectorydo usuwania katalogu z możliwością określenia wysłania go do kosza, czy nie.

Llewellyn
źródło
Problem z dołączeniem Microsoct.VisualBasic polega na tym, że koliduje z moim użyciem SearchOption w innym miejscu mojego programu (część funkcji GetFiles ()).
muttley91,
8
@rar Downvote nadal nie jest zasłużony, ponieważ w pytaniu nie określono, że „nie można odwoływać się do biblioteki VisualBasic z powodu konfliktu”. Które możesz łatwo rozwiązać w swoim kodzie. stackoverflow.com/questions/1317263/…
jsmith,
1
Ta metoda wydaje się wewnętrznie używać SHFileOperation, która nie obsługuje długich ścieżek i kończy się niepowodzeniem w przypadku ścieżek dłuższych niż MAX_PATH (nawet z prefiksem \\? \).
Melvyn
18

Poniższe rozwiązanie jest prostsze niż pozostałe:

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

Korzystając z tej biblioteki, możesz korzystać z innych funkcji kosza.

Po pierwsze, nie zapomnij dodać biblioteki „Microsoft Shell Controls And Automation” (z menu COM), aby móc korzystać z Shell32przestrzeni nazw. Będzie on dynamicznie połączony z Twoim projektem, zamiast być kompilowany wraz z Twoim programem.

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

sɐunıɔ ןɐ qɐp
źródło
8
Twoja odpowiedź byłaby lepsza, gdybyś skupił się na swoim rozwiązaniu, zamiast komentować inne odpowiedzi w pierwszym akapicie. Ponadto, ze względu na jasność, zastąpiłbym 10przez Shell32.ShellSpecialFolderConstants.ssfBITBUCKET. Warto wspomnieć o drugim parametrze to MoveHere, dotyczącym opcji takich jak 64 („Zachowaj informacje o cofnięciu, jeśli to możliwe”). Łączenie niektórych źródeł dokumentacji z MSDN byłoby dobrym wykończeniem.
grek40
2
Wygląda na to, że wywołanie MoveHere nie powoduje żadnego błędu: wywołanie go na nieistniejącym pliku kończy się niepowodzeniem! Zawodzi również po cichu na ścieżkach dłuższych niż MAX_CHARS, z prefiksem „\\? \” Lub bez niego ...
Melvyn
13

Niestety, aby usunąć plik z Kosza, musisz skorzystać z interfejsu API Win32. Wypróbuj następujący kod na podstawie tego postu . Wykorzystuje ogólną SHFileOperationfunkcję do operacji systemu plików za pośrednictwem powłoki systemu Windows.

Zdefiniuj następujące elementy (w klasie narzędzi jest prawdopodobnie najlepsze).

[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

Aby użyć go do usunięcia pliku, wysłania go do Kosza, potrzebujesz czegoś takiego:

var shf = new SHFILEOPSTRUCT();
shf.wFunc = FO_DELETE;
shf.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION;
shf.pFrom = @"C:\test.txt";
SHFileOperation(ref shf);
Noldorin
źródło
1
i podwójne null przerywają ciąg.
sean e
1
SHFileOperation nie obsługuje długich ścieżek i zakończy się niepowodzeniem w przypadku ścieżek dłuższych niż MAX_PATH (nawet z prefiksem \\? \).
Melvyn
Zauważ, że ta linia shf.pFrom = @"C:\test.txt";jest błędna - pFrom musi być zakończona podwójną wartością zerową. Należy dodać \0w pliku shf.pFrom = "C:\\text.txt\0";. Zobacz docs.microsoft.com/en-us/windows/desktop/api/shellapi/ ...
lindexi
1

Możesz SHFileOperationto zrobić za pomocą DllImport .

Brian R. Bondy
źródło
1
SHFileOperation nie obsługuje długich ścieżek i zakończy się niepowodzeniem w przypadku ścieżek dłuższych niż MAX_PATH (nawet z prefiksem \\? \).
Melvyn
1

Jest do tego wbudowana biblioteka .

Najpierw dodaj odniesienie Microsoft.VisualBasic Następnie dodaj ten kod:

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

Znalazłem to tutaj .

Maifee Ul Asad
źródło
1

Używam tej metody rozszerzenia, a następnie mogę po prostu użyć DirectoryInfo lub FileInfo i usunąć to.

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

przykład, jak to nazwać, może wyglądać tak:

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

}
Walter Vehoeven
źródło