【问题标题】:C# How to loop a large set of folders and files recursively without using a huge amount of memoryC#如何在不使用大量内存的情况下递归循环大量文件夹和文件
【发布时间】:2010-11-21 21:01:59
【问题描述】:

我想索引我所有的音乐文件并将它们存储在数据库中。 我有这个函数,我从音乐驱动器的根目录开始调用它。

start > ReadFiles(C:\music\);

ReadFiles(path){
   foreach(file)
      save to index;

   foreach(directory)
      ReadFiles(directory);
}

这很好用,但是在运行程序时,使用的内存量会不断增长,最后我的系统内存不足。

有没有人有更好的方法,不需要 4GB 的 RAM 来完成这项任务?

最好的问候,泰斯

【问题讨论】:

  • 请贴出实际代码。你的方法根本没有问题。
  • 递归不受可用内存的限制,而是受堆栈大小的限制,所以如果你的内存用完了,听起来你持有数据的时间太长了。
  • 我无法想象你有足够的音乐来占用这么大的空间。您确定您没有遇到堆栈溢出或在某个时间点进入了无限循环吗?
  • 解释“保存到索引”。它实际上是否将文件中的所有字节存储在正在运行的程序中的磁盘上?

标签: c# recursion out-of-memory fileinfo


【解决方案1】:

Alxandr 的基于队列的解决方案应该可以正常工作。

如果您使用的是 .NET 4.0,您还可以利用新的 Directory.EnumerateFiles 方法,该方法懒惰地枚举文件,而不会将它们全部加载到内存中:

void ReadFiles(string path)
{
    IEnumerable<string> files =
        Directory.EnumerateFiles(
            path,
            "*",
            SearchOption.AllDirectories); // search recursively

    foreach(string file in files)
        SaveToIndex(file);
}

【讨论】:

  • 不错。我不知道这个:-)
  • 这是一个很好的答案,但它仍然不能解决根本问题 - 如果您遇到内存问题,一定是内存占用过多。
  • @configurator,你可能是对的......但根据 OP 提供的信息,这是我能做的最好的 ;)
【解决方案2】:

您是否检查了除根目录之外的每个目录中出现的 ... 条目?

如果你不跳过这些,你将有一个无限循环。

【讨论】:

  • 他们不会出现在Directory.GetFilesDirectory.GetDirectories通常,您在.net 中工作时不应该遇到这种情况。
【解决方案3】:

您可以将其实现为队列。我认为(但我不确定)这会节省内存。至少它会释放你的堆栈。每当您找到一个文件夹时,您就将其添加到队列中,而每当您找到一个文件时,您就只需阅读它。这可以防止递归。

类似这样的:

Queue<string> dirs = new Queue<string>();
dirs.Enqueue("basedir");
while(dirs.Count > 0) {
    foreach(directory)
        dirs.Enqueue(directory);
    ReadFiles();
}

【讨论】:

  • 这不会节省内存。默认情况下,堆栈在 StackOverflow 之前只有 1 兆字节。如果他遇到 OutOfMemory,那就是另一个问题了。
  • 感谢所有回答。一切都有点帮助。我已经实现了一个队列机制,对不应该被索引的目录做了一些额外的检查,同时我发现我的 NHibernate 也需要一些微调。现在可以轻松索引超过 1TB。
【解决方案4】:

但请注意,如果您无权访问文件或路径太长或发生其他异常,则 EnumerateFiles() 将停止运行。这是我目前用来解决这些问题的方法:

public static List<string> getFiles(string path, List<string> files)
{
    IEnumerable<string> fileInfo = null;
    IEnumerable<string> folderInfo = null;
    try
    {
        fileInfo = Directory.EnumerateFiles(str);
    }
    catch
    {

    }
    if (fileInfo != null)
    {
        files.AddRange(fileInfo);
        //recurse through the subfolders
        fileInfo = Directory.EnumerateDirectories(str);
        foreach (string s in folderInfo)
        {
            try
            {
                getFiles(s, files);
            }
            catch
            {

            }
        }
    }
    return files;
}

使用示例:

List<string> files = new List<string>();
files = folder.getFiles(path, files);

我的解决方案基于此页面上的代码:http://msdn.microsoft.com/en-us/library/vstudio/bb513869.aspx

更新:可以在http://social.msdn.microsoft.com/Forums/vstudio/en-US/ae61e5a6-97f9-4eaa-9f1a-856541c6dcce/directorygetfiles-gives-me-access-denied?forum=csharpgeneral 找到更快的递归获取文件的方法。使用 Stack 对我来说是新事物(我什至不知道它存在),但该方法似乎有效。至少它列出了我的 C 和 D 分区上的所有文件,没有错误。

【讨论】:

    【解决方案5】:

    可能是连接文件夹,在进行递归时会导致无限循环,但我不确定,请自行检查并查看。链接:https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/mklink

    【讨论】:

      猜你喜欢
      • 2023-03-24
      • 1970-01-01
      • 2011-10-29
      • 1970-01-01
      • 1970-01-01
      • 2011-08-23
      • 1970-01-01
      • 2011-07-24
      相关资源
      最近更新 更多