迭代文件夹和子文件夹的最佳方式

Best way to iterate folders and subfolders

提问人:Rod 提问时间:3/3/2011 最后编辑:bluishRod 更新时间:11/24/2020 访问量:104930

问:

从指定位置开始,迭代文件夹和子文件夹以获取文件大小、文件总数和每个文件夹中文件夹的总大小的最佳方法是什么?

C# 子目录

评论

0赞 Andrew Orsich 3/3/2011
只有两个词:foreach 和 recursion。
1赞 Ritch Melton 3/3/2011
@Bugai13 - 对于CS作业来说,这是一个很好的建议,但.Net框架已经包含了该功能。顺便说一句,从迭代集合/枚举对象转向查询集合/枚举对象,甚至为集合/枚举对象提供工作是在现代上下文中解决该问题的正确方法。
1赞 HuBeZa 3/3/2011
请修正标题错别字:Interate 并将第一个字母大写。
0赞 Rod 3/3/2011
@Pekka起初我想探索不同的方法,但我想我会坚持使用 c#

答:

47赞 Lloyd 3/3/2011 #1

使用 Directory.GetFiles()。该页面的底部包含一个完全递归的示例。

注意:在使用 .NET 4 及更高版本时,请使用下面的 Chris Dunaway 的答案来获得更现代的方法。

// For Directory.GetFiles and Directory.GetDirectories
// For File.Exists, Directory.Exists
using System;
using System.IO;
using System.Collections;

public class RecursiveFileProcessor 
{
    public static void Main(string[] args) 
    {
        foreach(string path in args) 
        {
            if(File.Exists(path)) 
            {
                // This path is a file
                ProcessFile(path); 
            }               
            else if(Directory.Exists(path)) 
            {
                // This path is a directory
                ProcessDirectory(path);
            }
            else 
            {
                Console.WriteLine("{0} is not a valid file or directory.", path);
            }        
        }        
    }

    // Process all files in the directory passed in, recurse on any directories 
    // that are found, and process the files they contain.
    public static void ProcessDirectory(string targetDirectory) 
    {
        // Process the list of files found in the directory.
        string [] fileEntries = Directory.GetFiles(targetDirectory);
        foreach(string fileName in fileEntries)
            ProcessFile(fileName);

        // Recurse into subdirectories of this directory.
        string [] subdirectoryEntries = Directory.GetDirectories(targetDirectory);
        foreach(string subdirectory in subdirectoryEntries)
            ProcessDirectory(subdirectory);
    }
    
    // Insert logic for processing found files here.
    public static void ProcessFile(string path) 
    {
        Console.WriteLine("Processed file '{0}'.", path);       
    }
}

评论

1赞 quentin-starin 5/14/2011
需要注意的是:Directory.GetFiles() 对于包含大量文件(10 到 100 个数千个)的目录可能会非常慢。在这些情况下,到目前为止,我发现的最快方法实际上是启动一个进程来运行命令并重定向输出并解析它(或通过管道进入文件并读取它)。当然,除非我期望单个目录中有 50,000+ 个文件,否则我不会考虑这一点。dir
0赞 Lloyd 1/15/2013
实际上,调用等而不是使用可能会更快,尽管我敢肯定 .NET 无论如何都会解决这个问题。FindFirstFiledir
1赞 Rune Grimstad 3/3/2011 #2

若要循环访问文件和文件夹,通常使用 DirectoryInfoFileInfo 类型。FileInfo 类型具有一个 Length 属性,该属性返回文件大小(以字节为单位)。

我认为您必须编写自己的代码来遍历文件并计算总文件大小,但这应该是一个非常简单的递归函数。

8赞 safi 3/3/2011 #3

遍历所有目录子文件夹和文件,无论子文件夹和文件有多少。

string [] filenames;
 fname = Directory.GetFiles(jak, "*.*", SearchOption.AllDirectories).Select(x => Path.GetFileName(x)).ToArray();

然后,您可以从数组中通过循环或根据需要获得所需的内容。

评论

1赞 Anthony Wieser 10/2/2013
如果您的文件夹结构中存在循环,这将无限循环:请参阅 msdn.microsoft.com/en-us/library/ms143448.aspx
1赞 HuBeZa 3/3/2011 #4

请注意,您将需要执行验证检查。

string[] fileNames = Directory.GetFiles("c:\\", "*.*", SearchOption.AllDirectories);
int fileCount = fileNames.Count();
long fileSize = fileNames.Select(file => new FileInfo(file).Length).Sum(); // in bytes

评论

0赞 Rod 3/3/2011
什么类型的验证检查
0赞 HuBeZa 3/3/2011
@rod:检查是否(否则,)。我想不出别的了,但也许我错过了什么。Directory.ExistsDirectoryNotFoundException
59赞 Chris Dunaway 3/4/2011 #5

如果您使用的是 .NET 4,您可能希望使用 and 方法。如果您按照其他帖子的建议使用该方法,则在检索到所有条目之前,方法调用不会返回。如果您使用递归,这可能需要很长时间。System.IO.DirectoryInfo.EnumerateDirectoriesSystem.IO.DirectoryInfo.EnumerateFilesDirectory.GetFiles

文档中:

和方法的区别如下:EnumerateFilesGetFiles

  • 使用 时,可以在整个集合之前开始枚举对象的集合 返回。EnumerateFilesFileInfo
  • 使用 时,必须等待返回整个对象数组,然后才能访问该数组。GetFilesFileInfo

因此,当您处理许多文件和目录时,效率会更高。EnumerateFiles

评论

2赞 krowe2 8/15/2018
不得不跳过十几个使用 GetDirectory() 的示例来找到这个。对于 >50k 目录,速度太慢了。谢谢你拯救了我一天的罕见例子。
5赞 S4NT14G0 10/23/2019 #6

下面是一个使用上面 Peter 的建议和递归的示例。

using System;
using System.IO;

namespace FileSystemUtils
{
    class Program
    {
        static void Main(string[] args)
        {
            string folderPath = "C:\\docs";

            DirectoryInfo startDir = new DirectoryInfo(folderPath);

            RecurseFileStructure recurseFileStructure = new RecurseFileStructure();
            recurseFileStructure.TraverseDirectory(startDir);
        }

        public class RecurseFileStructure
        {
            public void TraverseDirectory(DirectoryInfo directoryInfo)
            {
                var subdirectories = directoryInfo.EnumerateDirectories();

                foreach (var subdirectory in subdirectories)
                {
                    TraverseDirectory(subdirectory);
                }

                var files = directoryInfo.EnumerateFiles();

                foreach (var file in files)
                {
                    HandleFile(file);
                }
            }

            void HandleFile(FileInfo file)
            {
                Console.WriteLine("{0}", file.Name);
            }
        }
    }
}