Gửi tệp vào thùng rác


83

Hiện tại tôi đang sử dụng chức năng sau

file.Delete();

Nhưng làm thế nào tôi có thể sử dụng chức năng này để gửi một tệp vào thùng rác thay vì chỉ xóa nó ngay lập tức?



3
Liên kết của @ UweKeim hiện đã chết, bạn có thể tìm thấy phiên bản định dạng .chm của Tạp chí MSDN (tháng 12 năm 2007) tại đây , bài báo có tên .NET Matters: IFileOperation in Windows Vistavà nó được tìm thấy trong Columnsthư mục.
jrh

Bài viết không mở được trong tệp .chm cho tôi. Liên kết này hoạt động: docs.microsoft.com/en-us/archive/msdn-magazine/2007/december/...
RandomEngy

Ngoài ra, bạn cần thêm FOFX_RECYCLEONDELETE = 0x00080000cờ hoạt động và cờ đó chỉ được hỗ trợ trên Windows 8 trở lên.
RandomEngy

Câu trả lời:


52

LƯU Ý: Điều này cũng không hoạt động với các ứng dụng không tương tác với giao diện người dùng như Windows Services

Trình bao bọc này có thể cung cấp cho bạn chức năng cần thiết:

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

Tôi không hiểu cách sử dụng cái này ... bạn có thể giải thích?
muttley91

4
Loại bỏ Pack = 1 nếu biên dịch cho nền tảng 64 bit (nếu không sẽ thất bại). Không có Pack = 1 được chỉ định, điều này sẽ hoạt động cho cả 32 bit và 64 bit. pinvoke.net/default.aspx/Structures/SHFILEOPSTRUCT.html
Sean

1
Khi sử dụng Pack = 1, một AccessViolationException đã được ném ra. Xóa nó đã thực hiện thủ thuật. 64-bit của Windows bằng cách này
P1nGu1n

1
Các yêu cầu để chạy mã này là gì? Tôi loại bỏ Pack = 1 nhưng nó vẫn không biên dịch. DllImport, DllImportAttribute, MarshalAs, MarshalAsAttribute, StructLayout, StructLayoutAttribute không tồn tại dưới dạng không gian tên. Bất kỳ sự giúp đỡ xin vui lòng nhờ :)
puretppc

1
SHFileOperation không xử lý các đường dẫn dài và sẽ không thành công với các đường dẫn dài hơn MAX_PATH (ngay cả với tiền tố \\? \).
Melvyn

155

Sử dụng FileSystem.DeleteFile và chỉ định RecycleOption phù hợp .

Mặc dù điều này sẽ hoạt động với Ứng dụng tương tác giao diện người dùng, nhưng nó sẽ không hoạt động với các ứng dụng tương tác không phải giao diện người dùng như ứng dụng Dịch vụ Windows.


17
@noldorin Đây là một giải pháp hoàn toàn tốt, không đáng bị phản đối. Tôi muốn tham khảo về lý do tại sao việc truy cập thư viện VisualBasic là "xấu xí".
jsmith

7
@noldorin: Đặc biệt trong trường hợp Microsoft.VisualBasic.FileIO.FileSystemnày về cơ bản giống như ví dụ được đăng ở đây bằng cách sử dụng SHFileOperation.
Dirk Vollmar

18
@Noldorin: Xấu xí hả? Đối với tôi, cách WinAPI là xấu hơn - ngoài ra, bạn có khả năng làm rối một thứ gì đó tốt hơn. Cá nhân tôi không thích cú pháp VB nhưng trong hợp ngữ, nó chỉ là ILvậy nên tôi không bận tâm. Hợp ngữ VB gọi cùng một hàm WinAPI btw.
Jaroslav Jandek

7
@Noldorin: Lỗi thời? Bạn đã Microsoft.VisualBasic.Compatibilitytình cờ nhầm việc lắp ráp ? Điều đó tôi sẽ tránh. Có vẻ như nó sẽ sớm không còn được dùng nữa (nó được sử dụng trong công cụ báo cáo RDL, v.v.).
Jaroslav Jandek

6
@Noldorin: Sử dụng lắp ráp khung dựng sẵn có vẻ như là một giải pháp tốt hơn so với việc ánh xạ kiểu cứng tới shell32.dll. Sử dụng các hội đồng khung, bạn nhận được sự thay đổi có thể di động và nhận được các tiến triển sau này. Lập bản đồ để các thư viện hệ thống, bạn mất tất cả cơ hội để trở nên lạc hậu bất kỳ ngày nào ...
fredlegrain

41

Từ MSDN :

Thêm một tham chiếu đến Microsoft.VisualBasic assembly. Lớp cần thiết được tìm thấy trong thư viện này.

Thêm câu lệnh using này vào đầu tệp using Microsoft.VisualBasic.FileIO;

Sử dụng FileSystem.DeleteFileđể xóa một tập tin, nó có tùy chọn để chỉ định thùng rác hoặc không.

Sử dụng FileSystem.DeleteDirectoryđể xóa một thư mục với tùy chọn để chỉ định gửi nó vào thùng rác hay không.


Vấn đề với việc bao gồm Microsoct.VisualBasic là nó xung đột với việc tôi sử dụng SearchOption ở nơi khác trong chương trình của tôi (một phần của hàm GetFiles ()).
muttley91

8
@rar Downvote vẫn không xứng đáng vì nó không được chỉ định trong câu hỏi rằng "Thư viện VisualBasic không thể được tham chiếu do xung đột." Điều mà bạn có thể dễ dàng giải quyết trong mã của mình. stackoverflow.com/questions/1317263/…
jsmith vào

1
Phương pháp này dường như sử dụng nội bộ SHFileOperation, không xử lý các đường dẫn dài và sẽ không thành công với các đường dẫn dài hơn MAX_PATH (ngay cả với tiền tố \\? \).
Melvyn

17

Giải pháp sau đây đơn giản hơn các giải pháp khác:

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

Bạn có thể sử dụng các chức năng khác của thùng rác bằng thư viện này.

Đầu tiên, đừng quên thêm thư viện "Microsoft Shell Controls And Automation" (từ trình đơn COM), để có thể sử dụng Shell32không gian tên. Nó sẽ được liên kết động với dự án của bạn, thay vì được biên dịch cùng với chương trình của bạn.

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


8
Câu trả lời của bạn sẽ tốt hơn khi bạn tập trung vào giải pháp của mình thay vì bình luận các câu trả lời khác trong đoạn đầu tiên. Ngoài ra, để rõ ràng, tôi muốn thay thế 10bằng Shell32.ShellSpecialFolderConstants.ssfBITBUCKET. Có thể cần nhắc đến tham số thứ hai MoveHere, liên quan đến các tùy chọn như 64 ("Giữ nguyên thông tin hoàn tác, nếu có thể"). Liên kết một số nguồn tài liệu từ MSDN sẽ là một kết thúc tốt đẹp.
grek40

2
Có vẻ như lệnh gọi tới MoveHere không xuất hiện bất kỳ lỗi nào: việc gọi nó trên một tệp không tồn tại không thành công! Nó cũng không hoạt động âm thầm trên các đường dẫn dài hơn MAX_CHARS, có hoặc không có tiền tố "\\? \" ...
Melvyn

13

Thật không may, bạn cần phải dùng đến API Win32 để xóa tệp vào Thùng rác. Hãy thử mã sau, dựa trên bài đăng này . Nó sử dụng SHFileOperationchức năng chung cho các hoạt động của hệ thống tệp thông qua Windows Shell.

Xác định những điều sau (trong một lớp tiện ích có lẽ là tốt nhất).

[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

Và để sử dụng nó để xóa một tệp, gửi nó vào Thùng rác, bạn cần một cái gì đó như:

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

1
và null kép chấm dứt chuỗi.
sean e

1
SHFileOperation không xử lý các đường dẫn dài và sẽ không thành công với các đường dẫn dài hơn MAX_PATH (ngay cả với tiền tố \\? \).
Melvyn

Lưu ý rằng dòng này shf.pFrom = @"C:\test.txt";là sai - pFrom phải được kết thúc bằng kép null. Bạn nên thêm \0vào tệp shf.pFrom = "C:\\text.txt\0";. Xem docs.microsoft.com/en-us/windows/desktop/api/shellapi/…
lindexi

1

Bạn có thể DllImport SHFileOperationđể làm điều này.


1
SHFileOperation không xử lý các đường dẫn dài và sẽ không thành công với các đường dẫn dài hơn MAX_PATH (ngay cả với tiền tố \\? \).
Melvyn

1

Tôi sử dụng phương pháp mở rộng này, sau đó tôi chỉ có thể sử dụng DirectoryInfo hoặc FileInfo và xóa nó.

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

một ví dụ về cách gọi nó có thể là:

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

thư viện tích hợp cho việc này.

Đầu tiên hãy thêm tham chiếu Microsoft.VisualBasic Sau đó thêm mã này:

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

Tôi đã tìm thấy điều này ở đây .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.