在控制深度的同时遍历目录 - C#
Walking through directory while controling depth - C#
我需要能够从目录和子目录中获取所有文件,但我想让用户可以选择子目录的深度。
即,不仅仅是当前目录或所有目录,他应该能够选择 1、2、3、4 目录等的深度。
我见过许多遍历目录树的示例,其中 none 似乎解决了这个问题。就个人而言,我对递归感到困惑......(我目前使用的)。我不确定在递归函数期间如何跟踪深度。
如有任何帮助,我们将不胜感激。
谢谢,
大卫
这是我当前的代码(我发现 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);
}
}
使用可以确定每个递归调用的最大深度变量,然后你不能 return 一旦达到所需的深度。
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);
}
}
让我们从重构代码开始,让它的工作更容易理解。
因此,这里的关键练习是递归地 return 所有匹配所需模式的文件,但仅限于一定深度。让我们先获取这些文件。
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();
现在我注意到你在数 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());
}
}
我需要能够从目录和子目录中获取所有文件,但我想让用户可以选择子目录的深度。 即,不仅仅是当前目录或所有目录,他应该能够选择 1、2、3、4 目录等的深度。
我见过许多遍历目录树的示例,其中 none 似乎解决了这个问题。就个人而言,我对递归感到困惑......(我目前使用的)。我不确定在递归函数期间如何跟踪深度。
如有任何帮助,我们将不胜感激。
谢谢, 大卫
这是我当前的代码(我发现 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);
}
}
使用可以确定每个递归调用的最大深度变量,然后你不能 return 一旦达到所需的深度。
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);
}
}
让我们从重构代码开始,让它的工作更容易理解。
因此,这里的关键练习是递归地 return 所有匹配所需模式的文件,但仅限于一定深度。让我们先获取这些文件。
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();
现在我注意到你在数 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());
}
}