C# 在控制depth-C时遍历目录#

C# 在控制depth-C时遍历目录#,c#,getfiles,C#,Getfiles,我需要能够从一个目录和子目录获取所有文件,但我想让用户选择子目录的深度。 也就是说,不仅仅是当前目录或所有目录,他还应该能够选择深度为1,2,3,4的目录等 我见过许多遍历目录树的例子,但没有一个能解决这个问题。就我个人而言,我对递归感到困惑。。。(我目前正在使用)。我不确定在递归函数中如何跟踪深度 任何帮助都将不胜感激 谢谢, 大卫 这是我当前的代码(我找到的): 使用可以在每次递归调用中递减的maxdepth变量,一旦达到所需的深度,就不能返回 static void FullDirList

我需要能够从一个目录和子目录获取所有文件,但我想让用户选择子目录的深度。 也就是说,不仅仅是当前目录或所有目录,他还应该能够选择深度为1,2,3,4的目录等

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

任何帮助都将不胜感激

谢谢, 大卫

这是我当前的代码(我找到的):


使用可以在每次递归调用中递减的maxdepth变量,一旦达到所需的深度,就不能返回

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);
    }

}

使用可以在每次递归调用中递减的maxdepth变量,一旦达到所需的深度,就不能返回

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);
    }

}

让我们从重构代码开始,使其工作更容易理解

因此,这里的关键练习是递归地返回与所需模式匹配的所有文件,但只返回一定深度的文件。让我们先去拿那些文件

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
范围内,然后按它们所属的文件夹对所有文件进行分组。我们这样做是为了下一步可以这样做:

    var directoriesFound = results.Count();
    var filesFound = results.SelectMany(fi => fi).Count();
现在我注意到您正在数
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());
    }
因此,完整的内容变成:

static void FullDirList(
    DirectoryInfo dir, string searchPattern, string excludeFolders, int maxSz, int depth)
{
    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;

    var directoriesFound = results.Count();
    var filesFound = results.SelectMany(fi => fi).Count();

    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());
    }
}

让我们从重构代码开始,使其工作更容易理解

因此,这里的关键练习是递归地返回与所需模式匹配的所有文件,但只返回一定深度的文件。让我们先去拿那些文件

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
范围内,然后按它们所属的文件夹对所有文件进行分组。我们这样做是为了下一步可以这样做:

    var directoriesFound = results.Count();
    var filesFound = results.SelectMany(fi => fi).Count();
现在我注意到您正在数
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());
    }
因此,完整的内容变成:

static void FullDirList(
    DirectoryInfo dir, string searchPattern, string excludeFolders, int maxSz, int depth)
{
    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;

    var directoriesFound = results.Count();
    var filesFound = results.SelectMany(fi => fi).Count();

    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());
    }
}


可能会给你一个提示递归?将参数添加到递归函数中,在每次子文件夹调用时递增该参数。这样你就知道你有多深了。@Thorarins,谢谢!我简直不敢相信我没有找到它——我找了好多我现在正在研究它,并将发回可能会给你一个提示递归?将参数添加到递归函数中,在每次子文件夹调用时递增该参数。这样你就知道你有多深了。@Thorarins,谢谢!我简直不敢相信我没有找到它——我找了好多我现在正在研究它,将发布back,而不是传递
depth
maxDepth
参数,只需传递
maxDepth
,在每个递归上递减1,并检查它是否被更改为使用@TimRogers suggestionHi伙计们,谢谢你们的回复。我已经试过了,但似乎不起作用。我正在调查-很快就会发回。-谢谢好吧,对不起,伙计们,它工作得很好。当涉及到递归时,我总是感到困惑。。。但现在它很简单!谢谢!不要传递
depth
maxDepth
参数,只需传递
maxDepth
,在每个递归上递减1,并检查它是否已更改为0以使用@TimRogers suggestionHi伙计们,谢谢你们的回复。我已经试过了,但似乎不起作用。我正在调查-很快就会发回。-谢谢好吧,对不起,伙计们,它工作得很好。当涉及到递归时,我总是感到困惑。。。但现在它很简单!谢谢!哇!这是什么语言!!☺ - 感谢您的工作和详细的解释。我将努力学习这一点,理解你写的东西这比前一种方法快/慢吗?@DaveyD-除非你有数十万个文件,否则你可能不会发现速度差异。我的代码应该更易于维护,因为它将递归代码分离出来,并将迭代代码线性化。哦,是的,是c。好的,谢谢-说得更像2-3000。我很喜欢你的代码设置,非常好。我还在想你写了什么!这看起来有点像sql…@DaveyD-
results
部分使用的是LINQ,类似于sql。你以前用过LINQ吗?我明白。不,我以前从未用过linq。看起来很有趣,功能强大而且有用!!。我也不太懂sql。我确实知道一点,但是一点也不舒服。哇!这是什么语言!!☺ - 感谢您的工作和详细的解释。我将努力学习这一点,理解你写的东西这比前一种方法快/慢吗?@DaveyD-除非你有数十万个文件,否则你可能不会发现速度差异。我的代码应该更易于维护,因为它将递归代码分离出来,并将迭代代码线性化。哦,是的,是c。好的,谢谢-说得更像2-3000。我很喜欢你的代码设置,非常好。我还在想你写了什么!这看起来有点像sql…@DaveyD-
results
部分使用的是LINQ,类似于sql。你以前用过LINQ吗?我明白。不,我以前从未用过linq。看起来很有趣,功能强大而且有用!!。我也不太懂sql