65.9K
CodeProject 正在变化。 阅读更多。
Home

CFileFindEx

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.93/5 (16投票s)

2005年9月13日

5分钟阅读

viewsIcon

94214

downloadIcon

1398

一个带有包含/排除过滤器的 CFileFind。

引言

本文档描述了如何使用 CFileFindEx,这是一个基于 MFC 类 CFileFind 的类,它允许您指定文件过滤器来控制返回哪些文件。该类可以插入到任何以前使用 CFileFind 类的地方,并且很容易理解。程序员可以使用 DOS 通配符或基于 ATL 正则表达式的包含或排除。

背景

我的公司 Rimage 制造高端 CD 和 DVD 生产设备。我专门从事的软件名为 QuickDisc。它是帮助桌面用户通过拖放收集文件并选择他们想要在创建光盘时使用的选项的接口。我们的设备会自动加载光驱,并使用我们开发的打印机在光盘上打印。QuickDisc 的一个问题是它不是一个很好的备份程序,因为它总是选择拖放到 UI 中的文件夹中的所有文件。本文档中包含的类是为了即将推出的版本而创建的,以便我们可以根据用户输入过滤文件。该类似乎很有用,并且足够通用,我认为其他人可能也会使用它。

使用代码

项目下载包含该类的源代码和一个实现其功能的程序。该类易于使用。程序员可以定义一个或多个包含或排除过滤器,格式类似于以下示例

*.cpp|*.h|*.rc

请注意,每个过滤器都用竖线 '|' 字符分隔。使用此字符是因为它不适用于 DOS 文件。如果上述内容包含在“包含”过滤器中,则只返回扩展名为 .cpp.h.rc 的文件。同样,如果上述过滤器被指定为“排除”过滤器,则返回除类型为 .cpp.h.rc 的文件之外的所有文件。

注意:无论名称或扩展名如何,文件夹始终被返回。

或者,可以使用 ATL 类 CAtlRegExp 定义的典型正则表达式语法的子集来指定包含和排除过滤器。允许使用以下语法

元字符 含义
. 匹配任何单个字符。
[ ] 表示一个字符类。匹配方括号内的任何字符(例如,[abc] 匹配“a”、“b”和“c”)。
^

如果此元字符出现在字符类的开头,它会否定该字符类。否定字符类匹配方括号内的任何字符以外的任何字符(例如,[^abc] 匹配除“a”、“b”和“c”之外的所有字符)。

如果 ^ 出现在正则表达式的开头,它会匹配输入的开头(例如,^[abc] 只会匹配以“a”、“b”或“c”开头的输入)。

-

在字符类中,表示字符范围(例如,[0-9] 匹配“0”到“9”之间的任何数字)。

?

表示前面的表达式是可选的:它最多匹配一次(例如,[0-9][0-9]? 匹配“2”和“12”)。

+

表示前面的表达式匹配一次或多次(例如,[0-9]+ 匹配“1”、“13”、“666”等)。

*

表示前面的表达式匹配零次或多次。

??, +?, *?

?+* 的非贪婪版本。这些匹配尽可能少,而贪婪版本则匹配尽可能多。例如:给定输入“<abc><def>”,<.*?> 匹配“<abc>”,而 <.*> 匹配“<abc><def>”。

\

转义字符:将下一个字符解释为字面量(例如,[0-9]+ 匹配一个或多个数字,但 [0-9]\+ 匹配一个数字后跟一个加号字符)。也用于缩写(例如,\a 表示任何字母数字字符;请参阅下表)。

$

在正则表达式的末尾,此字符匹配输入的末尾。示例:[0-9]$ 匹配输入末尾的一个数字。

|

交替运算符:分隔两个表达式,其中只有一个匹配(例如,T|the 匹配“The”或“the”)。

!

否定运算符:! 后面的表达式不匹配输入。示例:a!b 匹配后面不是“b”的“a”。

缩写 匹配
\a

任何字母数字字符:([a-zA-Z0-9])

\b

空白字符(空格):([ \\t])

\c

任何字母字符:([a-zA-Z])

\d

任何十进制数字:([0-9])

\h

任何十六进制数字:([0-9a-fA-F])

\n

换行符:(\r|(\r?\n))

\q

带引号的字符串:(\"[^\"]*\")|(\'[^\']*\')

\w

简单单词:([a-zA-Z]+)

\z

整数:([0-9]+)

例如,前面的过滤器列表可以输入为

^.*?\.cpp$|^.*?\.h$|^.*?\.rc$

正则表达式定义起来更麻烦,而且仅作为该类进行匹配方式的产物而存在,但一些有用的表达式可以完成

^[a-d].*?\.cpp$

只会包含(或排除)以 a、b、c 或 d 开头并具有 .cpp 扩展名的文件。使用此类进行的匹配始终不区分大小写。

该类实现如下面的示例所示。不要忘记包含 filefindex.h

#include "filefindex.h"

    CString csFilePath = _T("C:\\TestFiles");
    // Include all .doc, .xls, or .ppt files.
    CString csIncludeFilter = _T("*.doc|*.xls|*.ppt"); 
    // Note don't want .doc files that start with Tom
    CString csExcludeFilter = _T("Tom*.doc"); 

    // Check for files based on the critera the user filled out.
    CFileFindEx fileInfo;
    BOOL bWorked = fileInfo.FindFile(csFilePath,csIncludeFilter,
                           csExcludeFilter,bUseRegularExpression);
    if(bWorked) {
        do {
            bWorked = fileInfo.FindNextFile();
            // Do something with the files...
        } while(bWorked);
    }

关注点

任何使用过 CFileFind 的人都知道,在第一次调用 FindFile() 之前就调用 FindNextFile() 来使用第一个找到的文件是很烦人的。为了让这个类尽可能像原始类一样工作,复制这种不合逻辑的逻辑是棘手的。然而,我想我找到了一个方法,而且在我的测试中,它的运行速度似乎并不比原始类慢。我才刚开始使用这个类,所以它很新,但我已经通过包含的示例程序进行了大量测试,以确保我的版本和原始版本一样烦人,因为我们都对此有些习惯了。

历史

  • 2005 年 9 月 13 日 - 版本 1.0。
  • 2005 年 9 月 22 日 - 版本 1.1。
  • 修复了第二次(或更多次)调用 FindFile() 的问题。
  • 为类和演示添加了 Unicode 支持。
© . All rights reserved.