【C#】递归搜索指定目录下的指定项目(文件或目录)

---------------更新:201411201121---------------

主要更新说明:将原bool recurse参数改为int depth,这样可以指定递归深度,而不是笼统的是否递归

先别急着喷,请听我解释。

诚然可以使用现成的Directory类下的GetFiles、GetDirectories、GetFileSystemEntries这几个方法实现同样的功能,但请相信我不是蛋疼,原因是这几个方法在遇上【System Volume Information】这种目录时,极有可能会给你个拒绝访问的异常,想跳过都不行。关于这个问题,在MSDN也有说明:

http://msdn.microsoft.com/zh-cn/library/bb513869(v=vs.90).aspx

所以没办法,重新实现了一下。

实现说明:

- 仍然是基于对Directory类的几个方法的封装进行实现,只是没有使用它们的searchPattern和searchOption功能

- 将匹配模式由windows的通配符?、*改为正则匹配。一是让匹配更强大,二是要实现?*匹配还得做额外工作,没必要   匹配模式并没有默认添加首尾限定^$,即“abc"将会匹配所有包含该字串的项目,所以如果你要匹配首尾,请自行添加^$   忽略大小写匹配   如果不想搜索指定项目而是全部,请将regexPattern参数设为null,而不是.*,前者性能更好

- 可设置depth参数指定递归搜索的深度,默认为0,表示仅搜索顶级项目,正数表示往下钻几层,负数表示不限

- 可设置throwEx参数指示是否抛异常。默认是不抛,此时遇到不可访问的目录会跳过,继续遍历

- 之所以在foreach外层再套一层try-catch,是因为如果指定的dir就是不可访问的目录,那也可以避免异常。此时返回string[0]

- 之所以为获取项、获取文件、获取目录分别实现3个方法,而不是只实现一个获取项,另外两个重载,是因为只实现一个的话,foreach中要做的逻辑判断不少,考虑到方法是要递归的,所以循环中逻辑越少越好

- 之所以不做dir参数合法性检查,原因同上,判断越少越好。所以请用户调用前自行确保dir合法

废话完,上代码:

/// <summary>
/// 获取指定目录中的匹配项(文件或目录)
/// </summary>
/// <param name="dir">要搜索的目录</param>
/// <param name="regexPattern">项名模式(正则)。null表示忽略模式匹配,返回所有项</param>
/// <param name="depth">递归深度。负数表示不限,0表示仅顶级</param>
/// <param name="throwEx">是否抛异常</param>
/// <returns></returns>
public static string[] GetFileSystemEntries(string dir, string regexPattern = null, int depth = 0, bool throwEx = false)
{
    List<string> lst = new List<string>();

    try
    {
        foreach (string item in Directory.GetFileSystemEntries(dir))
        {
            try
            {
                if (regexPattern == null || Regex.IsMatch(Path.GetFileName(item), regexPattern, RegexOptions.IgnoreCase | RegexOptions.Multiline))
                { lst.Add(item); }

                //递归
                if (depth != 0 && (File.GetAttributes(item) & FileAttributes.Directory) == FileAttributes.Directory)
                { lst.AddRange(GetFileSystemEntries(item, regexPattern, depth - 1, throwEx)); }
            }
            catch { if (throwEx) { throw; } }
        }
    }
    catch { if (throwEx) { throw; } }

    return lst.ToArray();
}

/// <summary>
/// 获取指定目录中的匹配文件
/// </summary>
/// <param name="dir">要搜索的目录</param>
/// <param name="regexPattern">文件名模式(正则)。null表示忽略模式匹配,返回所有文件</param>
/// <param name="depth">递归深度。负数表示不限,0表示仅顶级</param>
/// <param name="throwEx">是否抛异常</param>
/// <returns></returns>
public static string[] GetFiles(string dir, string regexPattern = null, int depth = 0, bool throwEx = false)
{
    List<string> lst = new List<string>();

    try
    {
        foreach (string item in Directory.GetFileSystemEntries(dir))
        {
            try
            {
                bool isFile = (File.GetAttributes(item) & FileAttributes.Directory) != FileAttributes.Directory;

                if (isFile && (regexPattern == null || Regex.IsMatch(Path.GetFileName(item), regexPattern, RegexOptions.IgnoreCase | RegexOptions.Multiline)))
                { lst.Add(item); }

                //递归
                if (depth != 0 && !isFile) { lst.AddRange(GetFiles(item, regexPattern, depth - 1, throwEx)); }
            }
            catch { if (throwEx) { throw; } }
        }
    }
    catch { if (throwEx) { throw; } }

    return lst.ToArray();
}

/// <summary>
/// 获取指定目录中的匹配目录
/// </summary>
/// <param name="dir">要搜索的目录</param>
/// <param name="regexPattern">目fu录名模式(正则)。null表示忽略模式匹配,返回所有目录</param>
/// <param name="depth">递归深度。负数表示不限,0表示仅顶级</param>
/// <param name="throwEx">是否抛异常</param>
/// <returns></returns>
public static string[] GetDirectories(string dir, string regexPattern = null, int depth = 0, bool throwEx = false)
{
    List<string> lst = new List<string>();

    try
    {
        foreach (string item in Directory.GetDirectories(dir))
        {
            try
            {
                if (regexPattern == null || Regex.IsMatch(Path.GetFileName(item), regexPattern, RegexOptions.IgnoreCase | RegexOptions.Multiline))
                { lst.Add(item); }

                //递归
                if (depth != 0) { lst.AddRange(GetDirectories(item, regexPattern, depth - 1, throwEx)); }
            }
            catch { if (throwEx) { throw; } }
        }
    }
    catch { if (throwEx) { throw; } }

    return lst.ToArray();
}

- 文毕 -

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏玩转JavaEE

MongoDB文档查询操作(一)

上篇文章我们主要介绍了MongoDB的修改操作,本文我们来看看查询操作。 本文是MongoDB系列的第五篇文章,了解前面的文章有助于更好的理解本文: ---- ...

3616
来自专栏Hongten

spring+hibernate+struts2+compass整合

http://www.cnblogs.com/hongten/gallery/image/113449.html

1204
来自专栏GIS讲堂

数据库 连接(JOIN)

连接运算中有两种最为重要的连接,一种是等值连接(Equijoin),另一种是自然连接(Nature Join):等值连接是从关系R和S中的笛卡尔积中选取A,B属...

2103
来自专栏算法修养

LeetCode 138 Copy List with Random Pointer

LeetCode 138. Copy List with Random Pointer

1262
来自专栏Django Scrapy

day3 sql语句

sqlplus / as sysdba startup sqlplus scott/tiger vi .bash_profile 容宽不够 set lines ...

3109
来自专栏JavaEdge

为什么java中用枚举实现单例模式会更好代码简洁

代码简洁 这是迄今为止最大的优点,如果你曾经在Java5之前写过单例模式代码,那么你会知道即使是使用双检锁你有时候也会返回不止一个实例对象。虽然这种问题通过...

5324
来自专栏Fish

android文件存储

为了输出数据,要把list中存储的写到一个txt文件里,就顺手学了一下 文件存储的方法,说是学,其实又是百度之后复制粘贴。不过学到了一个关于java中的一个知识...

2299
来自专栏IT可乐

Java设计模式之(一)------单例模式

1、什么是单例模式?   采取一定的办法保证在整个软件系统中,单例模式确保对于某个类只能存在一个实例。有如下三个特点:   ①、单例类只能有一个实例   ②、单...

2177
来自专栏java达人

sql server 获取每一个类别中值最大的一条数据

数据如下: name val memo a 2 a2(a的第二个值) a 1 a1--a的第一个值 a 3 a3:a的第三...

1819
来自专栏菩提树下的杨过

AS3中的单件(Singleton)模式

单件(singleton)模式在c#中是最容易实现的模式,其主要用意就在于限制使用者用new来创建多个实例。但在as3中,构造函数必须是public的(语法本身...

2185

扫码关注云+社区

领取腾讯云代金券