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

Posted

技术标签:

【中文标题】迭代文件夹和子文件夹的最佳方法【英文标题】:Best way to iterate folders and subfolders 【发布时间】:2011-07-08 01:46:13 【问题描述】:

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

【问题讨论】:

只有两个词:foreach 和 recursion.. @Bugai13 - 这是一个很好的 CS 作业建议,但 .Net 框架已经包含该功能。顺便说一句,从迭代集合/可枚举对象转向查询集合/可枚举对象,甚至让集合/可枚举对象完成工作是在现代环境中解决该问题的正确方法。 请修正标题错字:in将第一个字母大写。 @Pekka 起初我想探索不同的方式,但我想我会坚持使用 c# 【参考方案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);       
    

【讨论】:

一个警告:Directory.GetFiles() 对于包含大量文件(10 到 100 万个)的目录可能会非常缓慢。在这些情况下,到目前为止我发现的最快方法实际上是启动一个进程来运行dir 命令并重定向输出并解析它(或管道到文件中并读取它)。当然,除非我希望单个目录中有 50,000 多个文件,否则我不会考虑这一点。 实际上,使用FindFirstFile 等而不是使用dir 可能会更快,尽管我确信.NET 无论如何都可以做到这一点。【参考方案2】:

这是一个使用上述彼得建议和递归的示例。

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

【讨论】:

【参考方案3】:

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

来自documentation:

EnumerateFilesGetFiles 方法的区别如下:

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

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

【讨论】:

不得不跳过十几个使用 GetDirectory() 的例子来找到这个。使用 > 50k 目录时,它太慢了。感谢这个罕见的例子挽救了我的一天。【参考方案4】:

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

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

【讨论】:

什么类型的验证检查 @rod:检查是否为Directory.Exists(否则为DirectoryNotFoundException)。我想不出别的,但也许我错过了什么。【参考方案5】:

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

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

然后从数组中你可以通过循环或你想要的方式得到你想要的。

【讨论】:

如果您的文件夹结构中有循环,这将无限循环:请参阅msdn.microsoft.com/en-us/library/ms143448.aspx【参考方案6】:

要遍历文件和文件夹,您通常会使用 DirectoryInfo 和 FileInfo 类型。 FileInfo 类型有一个 Length 属性,它以字节为单位返回文件大小。

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

【讨论】:

以上是关于迭代文件夹和子文件夹的最佳方法的主要内容,如果未能解决你的问题,请参考以下文章

在python中迭代大型csv文件中的行的最佳方法,写入新的

在多个文件中进行查找/替换的最佳方法?

逐行迭代文本文件的内容 - 是不是有最佳实践? (与 PMD 的 AssignmentInOperand 相比)

递归方法删除文件夹(包含所有文件和子文件)

获取将返回列表的文件夹和子文件夹中的所有文件的方法

批量改变文件夹和子文件夹中图片格式的两种方法