在控制深度的同时遍历目录 - C#

时间:2015-07-06 11:45:06

标签: c# getfiles

我需要能够从目录和子目录中获取所有文件,但我想为用户提供选择子目录深度的选项。 即,不仅仅是当前目录或所有目录,但他应该能够选择1,2,3,4目录的深度等。

我已经看过很多遍历目录树的例子,似乎没有一个能解决这个问题。就个人而言,我对递归感到困惑......(我目前正在使用它)。我不确定在递归函数中如何跟踪深度。

非常感谢任何帮助。

谢谢, 大卫

这是我当前的代码(我发现here):

    static void FullDirList(DirectoryInfo dir, string searchPattern, string excludeFolders, int maxSz, string depth)
    {

        try
        {
            foreach (FileInfo file in dir.GetFiles(searchPattern))
            {

                if (excludeFolders != "")
                    if (Regex.IsMatch(file.FullName, excludeFolders, RegexOptions.IgnoreCase)) continue;

                myStream.WriteLine(file.FullName);
                MasterFileCounter += 1;

                if (maxSz > 0 && myStream.BaseStream.Length >= maxSz)
                {
                    myStream.Close();
                    myStream = new StreamWriter(nextOutPutFile());
                }

            }
        }
        catch
        {
            // make this a spearate streamwriter to accept files that failed to be read.
            Console.WriteLine("Directory {0}  \n could not be accessed!!!!", dir.FullName);
            return;  // We alredy got an error trying to access dir so dont try to access it again
        }

        MasterFolderCounter += 1;

        foreach (DirectoryInfo d in dir.GetDirectories())
        {
            //folders.Add(d);
            // if (MasterFolderCounter > maxFolders) 
            FullDirList(d, searchPattern, excludeFolders, maxSz, depth);
        }

    }

2 个答案:

答案 0 :(得分:2)

使用maxdepth varibale,每次递归调用都可以递减,然后一旦达到所需深度就不能返回。

static void FullDirList(DirectoryInfo dir, string searchPattern, string excludeFolders, int maxSz, int maxDepth)
{

    if(maxDepth == 0)
    {
        return;
    }

    try
    {
        foreach (FileInfo file in dir.GetFiles(searchPattern))
        {

            if (excludeFolders != "")
                if (Regex.IsMatch(file.FullName, excludeFolders, RegexOptions.IgnoreCase)) continue;

            myStream.WriteLine(file.FullName);
            MasterFileCounter += 1;

            if (maxSz > 0 && myStream.BaseStream.Length >= maxSz)
            {
                myStream.Close();
                myStream = new StreamWriter(nextOutPutFile());
            }

        }
    }
    catch
    {
        // make this a spearate streamwriter to accept files that failed to be read.
        Console.WriteLine("Directory {0}  \n could not be accessed!!!!", dir.FullName);
        return;  // We alredy got an error trying to access dir so dont try to access it again
    }

    MasterFolderCounter += 1;

    foreach (DirectoryInfo d in dir.GetDirectories())
    {
        //folders.Add(d);
        // if (MasterFolderCounter > maxFolders) 
        FullDirList(d, searchPattern, excludeFolders, maxSz, depth - 1);
    }

}

答案 1 :(得分:2)

让我们从重构代码开始,让它的工作更容易理解。

因此,这里的关键练习是以递归方式返回与所需模式匹配的所有文件,但仅返回到某个深度。我们先得到这些文件。

<delimited-identifiers/>

这简化了递归文件的工作。

但是你会注意到它没有根据public static IEnumerable<FileInfo> GetFullDirList( DirectoryInfo dir, string searchPattern, int depth) { foreach (FileInfo file in dir.GetFiles(searchPattern)) { yield return file; } if (depth > 0) { foreach (DirectoryInfo d in dir.GetDirectories()) { foreach (FileInfo f in GetFullDirList(d, searchPattern, depth - 1)) { yield return f; } } } } 参数排除文件。我们现在就解决这个问题吧。让我们开始构建excludeFolders

第一行是

FullDirList

这将获取并获取所有文件,将它们限制为 var results = from fi in GetFullDirList(dir, searchPattern, depth) where String.IsNullOrEmpty(excludeFolders) || !Regex.IsMatch(fi.FullName, excludeFolders, RegexOptions.IgnoreCase) group fi.FullName by fi.Directory.FullName; ,然后按照它们所属的文件夹对所有文件进行分组。我们这样做是为了让我们可以做到这一点:

excludeFolders

现在我注意到你在计算 var directoriesFound = results.Count(); var filesFound = results.SelectMany(fi => fi).Count(); &amp; MasterFileCounter

您可以轻松地写道:

MasterFolderCounter

现在,要写出这些文件,您似乎正在尝试将文件名聚合到单独的文件中,但保留文件的最大长度( MasterFolderCounter+= results.Count(); MasterFileCounter += results.SelectMany(fi => fi).Count(); )。

以下是如何做到这一点:

maxSz

现在编写文件变得非常简单:

    var aggregateByLength =
        results
            .SelectMany(fi => fi)
            .Aggregate(new [] { new StringBuilder() }.ToList(),
                (sbs, s) =>
                {
                    var nl = s + Environment.NewLine;
                    if (sbs.Last().Length + nl.Length > maxSz)
                    {
                        sbs.Add(new StringBuilder(nl));
                    }
                    else
                    {
                        sbs.Last().Append(nl);
                    }
                    return sbs;
                });

所以,完整的事情变成了:

    foreach (var sb in aggregateByLength)
    {
        File.WriteAllText(nextOutPutFile(), sb.ToString());
    }