c#|C#中使用SHFileOperation调用Windows的复制文件对话框

C#中,复制文件的操作十分简单,System.IO.File.Copy()。但是用过的同学都知道,这个方法在复制大文件的时候非常不好用,因为它会阻塞当期线程直到文件复制完毕,要终止也麻烦(把复制操作放到线程中,通过终止线程来终止操作)。如果能使用Explorer中复制文件时的对话框,就能直观的显示复制进度,并且能随时取消复制操作。
要实现Explorer中复制粘贴时的对话框,可以自己编写相关代码,使用异步读写文件字节流的方式来复制文件,这种方式我们今天就不讨论了;
另外一种方法,是使用Windows API SHFileOperation来达到目的;
【c#|C#中使用SHFileOperation调用Windows的复制文件对话框】定义API:

/// /// 映射API方法/// /// /// [DllImport("shell32.dll", SetLastError = true, CharSet = CharSet.Unicode)]private static extern int SHFileOperation(SHFILEOPSTRUCT lpFileOp); /// /// 多个文件路径的分隔符/// private const string FILE_SPLITER = "\0"; /// /// Shell文件操作数据类型/// [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]private class SHFILEOPSTRUCT{public IntPtr hwnd; /// /// 设置操作方式/// public wFunc wFunc; /// /// 源文件路径/// public string pFrom; /// /// 目标文件路径/// public string pTo; /// /// 允许恢复/// public FILEOP_FLAGS fFlags; /// /// 监测有无中止/// public bool fAnyOperationsAborted; public IntPtr hNameMappings; /// /// 设置标题/// public string lpszProgressTitle; } /// /// 文件操作方式/// private enum wFunc{/// /// 移动/// FO_MOVE = 0x0001,/// /// 复制/// FO_COPY = 0x0002,/// /// 删除/// FO_DELETE = 0x0003,/// /// 重命名/// FO_RENAME = 0x0004} /// /// fFlags枚举值,/// 参见:http://msdn.microsoft.com/zh-cn/library/bb759795(v=vs.85).aspx/// private enum FILEOP_FLAGS{ //////pTo 指定了多个目标文件,而不是单个目录///The pTo member specifies multiple destination files (one for each source file) rather than one directory where all source files are to be deposited.///FOF_MULTIDESTFILES = 0x1,//////不再使用///Not currently used.///FOF_CONFIRMMOUSE = 0x2,//////不显示一个进度对话框///Do not display a progress dialog box.///FOF_SILENT = 0x4,//////碰到有抵触的名字时,自动分配前缀///Give the file being operated on a new name in a move, copy, or rename operation if a file with the target name already exists.///FOF_RENAMEONCOLLISION = 0x8,//////不对用户显示提示///Respond with "Yes to All" for any dialog box that is displayed.///FOF_NOCONFIRMATION = 0x10,//////填充 hNameMappings 字段,必须使用 SHFreeNameMappings 释放///If FOF_RENAMEONCOLLISION is specified and any files were renamed, assign a name mapping object containing their old and new names to the hNameMappings member.///FOF_WANTMAPPINGHANDLE = 0x20,//////允许撤销///Preserve Undo information, if possible. If pFrom does not contain fully qualified path and file names, this flag is ignored.///FOF_ALLOWUNDO = 0x40,//////使用 *.* 时, 只对文件操作///Perform the operation on files only if a wildcard file name (*.*) is specified.///FOF_FILESONLY = 0x80,//////简单进度条,意味着不显示文件名。///Display a progress dialog box but do not show the file names.///FOF_SIMPLEPROGRESS = 0x100,//////建新目录时不需要用户确定///Do not confirm the creation of a new directory if the operation requires one to be created.///FOF_NOCONFIRMMKDIR = 0x200,//////不显示出错用户界面///Do not display a user interface if an error occurs.///FOF_NOERRORUI = 0x400,////// 不复制 NT 文件的安全属性///Do not copy the security attributes of the file.///FOF_NOCOPYSECURITYATTRIBS = 0x800,////// 不递归目录///Only operate in the local directory. Don't operate recursively into subdirectories.///FOF_NORECURSION = 0x1000,//////Do not move connected files as a group. Only move the specified files.///FOF_NO_CONNECTED_ELEMENTS = 0x2000,//////Send a warning if a file is being destroyed during a delete operation rather than recycled. This flag partially overrides FOF_NOCONFIRMATION.///FOF_WANTNUKEWARNING = 0x4000,//////Treat reparse points as objects, not containers.///FOF_NORECURSEREPARSE = 0x8000,}

使用方法:
public static int Copy(string sourceFiles, string targetFiles){SHFILEOPSTRUCT pm = new SHFILEOPSTRUCT(); pm.wFunc = wFunc.FO_COPY; //设置对话框标题,在win7中无效pm.lpszProgressTitle = "复制文件"; pm.pFrom = sourceFiles; pm.pTo = targetFiles; pm.fFlags = FILEOP_FLAGS.FOF_NOCONFIRMATION | FILEOP_FLAGS.FOF_MULTIDESTFILES | FILEOP_FLAGS.FOF_ALLOWUNDO; return SHFileOperation(pm); }

返回值如果为0表示复制成功,非0表示出错,返回值代表意义可参看http://msdn.microsoft.com/zh-cn/library/bb762164(v=vs.85).aspx
这是复制一个文件的,那么如果需要复制多个文件呢?注意上面的pm.pFrom和pm.pTo这两个string属性,传入的字符串可以为多个文件,需要用’\0’作为两个文件路径的分隔符,最后要以’\0\0’(两个)作为结尾,然后还要注意pFrom和pTo文件个数应该一致;(关于使用’\0’分割,一开始我真是想到,试过用分号,逗号,回车符,发现都不行,后来还是看了MSDN才发现应该用’\0’的。)
如果你想要源为文件列表,目标为一个目录,那么,pTo就改成目录,同时要注意pm.fFlags就不要加上FILEOP_FLAGS.FOF_MULTIDESTFILES;
当然,SHFileOperation并不仅仅可以用于复制文件,从上面的wFunc枚举我们可以发现除了复制还有移动、删除、重命名的操作;使用方法也是大同小异。我将其封装于一个类中,并提供多种重载。
原来上传的附件有问题:ShellFileOperation.rar
请下载这个:ShellFileOperation(修正).rar我封装的类里面使用到了IEnumerable.Count(),这个需要using System.Linq; 当然这个与主功能没关系,如果你使用Framework版本低于3.5,可以将IEnumerable.Count()换成别的实现。感谢二楼“蜗牛往前走”的提示!
转载于:https://www.cnblogs.com/jifengg/archive/2013/05/13/3076131.html

    推荐阅读