C#中使用API(SHFileOperation)进行文件操作,特别说明了回收站相关参数
2010-03-28 18:22
661 查看
项目中使用了磁盘阵列柜,每秒有上百兆的数据存入磁盘,这就有了从磁盘删除文件的需求。为了满足这一需求,我做了一个用于删除过期数据的系统服务。说来这个东西本身是很简单的,但是由于数据量的巨大价值磁盘阵列空间容量的巨大(8T,1T=1024G),在实际操作中也遇到了不少麻烦。
需求很简单,遍历磁盘指定目录下的所有目录和文件,根据一个比较规则判定文件是否过期,如果过期就删除。最初的设计也很简单,三个步骤:遍历 -> 过期检测 -> 删除。有了需求和程序框架设计,于是开始实施。
在C#中,DirectoryInfo和FileInfo为我们提供了足够的方法,在程序第一次成型的时候我主要使用了下面的方法:
遍历:DirectoryInfo.GetDirectories(),DirectoryInfo.GetFiles()
删除:DirectoryInfo.Delete(),FileInfo.Delete()
本机使用时效果很好,但实际上服务器运行就出现了问题:磁盘过大,文件过多,导致执行效率极其缓慢,甚至无法遍历出文件夹和文件,删除一个文件就需要好几分钟。当然,这和磁盘I/O有关,需要在有限的I/O下提高效率。
为了提高效率,改用API的方式。使用SHFileOperation来进行文件、文件夹的删除操作。代码见下:
使用API之后,效率明显提高,遍历和删除文件速度明显加快。但尤其值得注意的是:SHFILEOPSTRUCT.fFlags属性,它指定了一些删除操作中的其他属性。这里我想特别提出的是FOF_ALLOWUNDO,望文生义,允许撤销那应当就是删除到回收站了。MSDN上对这个属性的解释是:
Preserve undo information, if possible. Operations can be undone only from the same process that performed the original operation. If, despite earlier warnings against doing so, pFrom does not contain fully-qualified path and file names, this flag is ignored.
它指出:
如果可能,系统将默认这些操作可以撤销。
如果文件、文件夹路径不是全路径,将忽略此属性。
可以看出,这段文字并没有很具体地介绍这个属性。经过我的实际实践得出:
设置 lpFileOp.fFlags |= FOF_ALLOWUNDO和不设置这个属性的效果是一样的,即默认会删除到回收站。
要想直接删除,不进入回收站,我们必须设置lpFileOp.fFlags &= ~FILEOP_FLAGS.FOF_ALLOWUNDO;这一点尤为重要。
当然,这个API除了可以进行删除操作之外,还可以进行其他的文件、文件夹操作,此处不表。
需求很简单,遍历磁盘指定目录下的所有目录和文件,根据一个比较规则判定文件是否过期,如果过期就删除。最初的设计也很简单,三个步骤:遍历 -> 过期检测 -> 删除。有了需求和程序框架设计,于是开始实施。
在C#中,DirectoryInfo和FileInfo为我们提供了足够的方法,在程序第一次成型的时候我主要使用了下面的方法:
遍历:DirectoryInfo.GetDirectories(),DirectoryInfo.GetFiles()
删除:DirectoryInfo.Delete(),FileInfo.Delete()
本机使用时效果很好,但实际上服务器运行就出现了问题:磁盘过大,文件过多,导致执行效率极其缓慢,甚至无法遍历出文件夹和文件,删除一个文件就需要好几分钟。当然,这和磁盘I/O有关,需要在有限的I/O下提高效率。
为了提高效率,改用API的方式。使用SHFileOperation来进行文件、文件夹的删除操作。代码见下:
using System; using System.Runtime.InteropServices; namespace FileDirectoryAPI { public class DeleteAPI { [DllImport("shell32.dll")] private static extern int SHFileOperation(ref SHFILEOPSTRUCT lpFileOp); /// <summary> /// 执行删除。成功返回空,否则返回错误信息。 /// </summary> /// <param name="path"></param> /// <returns></returns> public static string Delete(string path) { SHFILEOPSTRUCT lpFileOp = new SHFILEOPSTRUCT(); lpFileOp.wFunc = wFunc.FO_DELETE; lpFileOp.pFrom = path + "\0"; lpFileOp.fFlags = FILEOP_FLAGS.FOF_NOCONFIRMATION | FILEOP_FLAGS.FOF_NOERRORUI | FILEOP_FLAGS.FOF_SILENT; lpFileOp.fFlags &= ~FILEOP_FLAGS.FOF_ALLOWUNDO; lpFileOp.fAnyOperationsAborted = false; int n = SHFileOperation(ref lpFileOp); if (n == 0) return string.Empty; string tmp = GetErrorString(n); //.av 文件正常删除了但也提示 402 错误,不知道为什么。屏蔽之。 if ((path.ToLower().EndsWith(".av") && n.ToString("X") == "402")) return string.Empty; return string.Format("{0}({1})", tmp, path); } private struct 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 } private enum FILEOP_FLAGS { FOF_MULTIDESTFILES = 0x0001, //pTo 指定了多个目标文件,而不是单个目录 FOF_CONFIRMMOUSE = 0x0002, FOF_SILENT = 0x0044, // 不显示一个进度对话框 FOF_RENAMEONCOLLISION = 0x0008, // 碰到有抵触的名字时,自动分配前缀 FOF_NOCONFIRMATION = 0x10, // 不对用户显示提示 FOF_WANTMAPPINGHANDLE = 0x0020, // 填充 hNameMappings 字段,必须使用 SHFreeNameMappings 释放 FOF_ALLOWUNDO = 0x40, // 允许撤销 FOF_FILESONLY = 0x0080, // 使用 *.* 时, 只对文件操作 FOF_SIMPLEPROGRESS = 0x0100, // 简单进度条,意味者不显示文件名。 FOF_NOCONFIRMMKDIR = 0x0200, // 建新目录时不需要用户确定 FOF_NOERRORUI = 0x0400, // 不显示出错用户界面 FOF_NOCOPYSECURITYATTRIBS = 0x0800, // 不复制 NT 文件的安全属性 FOF_NORECURSION = 0x1000 // 不递归目录 } //更多错误代码见:ms-help://MS.MSDNQTR.v90.chs/shellcc/platform/shell/reference/functions/shfileoperation.htm private static string GetErrorString(int n) { if (n == 0) return string.Empty; string code = n.ToString("X").ToUpper(); switch (code) { case "74": return "The source is a root directory, which cannot be moved or renamed."; case "76": return "Security settings denied access to the source."; case "7C": return "The path in the source or destination or both was invalid."; case "10000": return "An unspecified error occurred on the destination."; case "402": return "An unknown error occurred. This is typically due to an invalid path “
+"in the source or destination. This error does not occur on Windows Vista and later."; default: return code; } } } }
使用API之后,效率明显提高,遍历和删除文件速度明显加快。但尤其值得注意的是:SHFILEOPSTRUCT.fFlags属性,它指定了一些删除操作中的其他属性。这里我想特别提出的是FOF_ALLOWUNDO,望文生义,允许撤销那应当就是删除到回收站了。MSDN上对这个属性的解释是:
Preserve undo information, if possible. Operations can be undone only from the same process that performed the original operation. If, despite earlier warnings against doing so, pFrom does not contain fully-qualified path and file names, this flag is ignored.
它指出:
如果可能,系统将默认这些操作可以撤销。
如果文件、文件夹路径不是全路径,将忽略此属性。
可以看出,这段文字并没有很具体地介绍这个属性。经过我的实际实践得出:
设置 lpFileOp.fFlags |= FOF_ALLOWUNDO和不设置这个属性的效果是一样的,即默认会删除到回收站。
要想直接删除,不进入回收站,我们必须设置lpFileOp.fFlags &= ~FILEOP_FLAGS.FOF_ALLOWUNDO;这一点尤为重要。
当然,这个API除了可以进行删除操作之外,还可以进行其他的文件、文件夹操作,此处不表。
相关文章推荐
- C#中使用API(SHFileOperation)进行文件操作,特别说明了回收站相关参数
- c#中使用api(shfileoperation)进行文件操作,特别详解了回收站相关参数
- 使用servlet3.0提供的API来进行文件的上传操作
- 使用C# 怎么生成.db后缀的文件,并且能够使用sql语言进行读取等 操作
- C#实现多级子目录Zip压缩解压实例 NET4.6下的UTC时间转换 [译]ASP.NET Core Web API 中使用Oracle数据库和Dapper看这篇就够了 asp.Net Core免费开源分布式异常日志收集框架Exceptionless安装配置以及简单使用图文教程 asp.net core异步进行新增操作并且需要判断某些字段是否重复的三种解决方案 .NET Core开发日志
- 如何使用C#对虚拟磁盘文件(VHD)进行操作
- c#使用API进行模拟鼠标点击 底层操作同样简单
- 使用JAVA自带的zipInputStream进行解压缩文件包的操作
- c# 使用WINAPI 进行读取写入配置文件
- C#使用ICSharpCode.SharpZipLib.dll进行文件的压缩与解压功能
- 使用C#和Excel进行报表开发(五)-操作单元格边框和颜色
- C#项目中操作Excel文件——使用NPOI库
- 使用C#和Excel进行报表开发(五)-操作单元格边框和颜色
- 使用文件映射的方式进行共享数据中CreateFileMapping、MapViewOfFile函数参数说明
- C#操作Excel的类以及其使用举例说明
- C#操作txt文件,进行清空添加操作的小例子
- 使用C#和Excel进行报表开发(五)-操作单元格边框和颜色
- android出现注: 某些输入文件使用或覆盖了已过时的 API。 注: 有关详细信息, 请使用 -Xlint:deprecation 重新编译。 注: 某些输入文件使用了未经检查或不安全的操作。 注
- [ElasticSearch]使用 java API 进行CRUD操作
- C#调用GPG命令进行加密解密文件操作