列出一个目录+子目录中的所有文件和目录

Posted

技术标签:

【中文标题】列出一个目录+子目录中的所有文件和目录【英文标题】:List all files and directories in a directory + subdirectories 【发布时间】:2012-09-02 04:25:08 【问题描述】:

我想列出目录和该目录的子目录中包含的每个文件和目录。如果我选择 C:\ 作为目录,程序将获取它可以访问的硬盘驱动器上每个文件和文件夹的每个名称。

列表可能看起来像

fd\1.txt fd\2.txt fd\a\ fd\b\ fd\a\1.txt fd\a\2.txt fd\a\a\ fd\a\b\ fd\b\1.txt fd\b\2.txt fd\b\a fd\b\b fd\a\a\1.txt fd\a\a\a\ fd\a\b\1.txt fd\a\b\a fd\b\a\1.txt fd\b\a\a\ fd\b\b\1.txt fd\b\b\a

【问题讨论】:

浏览 System.IO 命名空间中的 classes 和 methods 可能会对您有所帮助。 查看this question,并删除他匹配模式的部分。 How to recursively list all the files in a directory in C#?的可能重复 【参考方案1】:

请尝试使用以下代码读取所有目录和包含文件的子目录

class Program

    static string _rootPath = @"D:\My Project\App_Data";
   
    static void Main(string[] args)
    
        ReadDirectories(_rootPath);

        Console.ReadKey();
    

    public static void ReadDirectories(string path, string directoryName = "")
    
        if (!string.IsNullOrEmpty(directoryName))
        
            Console.WriteLine("DIRECTORY NAME - 0", directoryName);
            path = @$"path\directoryName";
        

        DirectoryInfo dir_place = new DirectoryInfo(path);

        FileInfo[] Files = dir_place.GetFiles();
        foreach (FileInfo i in Files)
        
            Console.WriteLine("0 - FILE NAME - 1", directoryName, i.Name);
        

        DirectoryInfo[] directories = dir_place.GetDirectories();
        foreach (var directory in directories)
        
            ReadDirectories(path, directory.Name);
        ;
    

调用“ReadDirectories”方法直到扫描完最后一个目录。

【讨论】:

【参考方案2】:

一个迟到的答案,但我认为有人可能会从中受益。支持错误处理和返回相对路径的基于堆栈的迭代版本启动器:

private static IEnumerable<string> TryEnumerate(Func<IEnumerable<string>> action)

    try
    
        return action.Invoke();
    
    catch
    
       //TODO logging
       return Enumerable.Empty<string>();
    


private static IEnumerable<string> FindFilesAndDirectories(string dir, bool returnRelativePaths = false, string filePattern="*.*")

    var searchStack = new Stack<string>();
    searchStack.Push(dir);
    var initialDirectory = new DirectoryInfo(dir).FullName;
    var initialDirLength = initialDirectory.Length;

    while (searchStack.Count > 0)
    
        var currentDirectory = searchStack.Pop();
            
        yield return (returnRelativePaths && 
                string.Compare(currentDirectory, initialDirectory, StringComparison.OrdinalIgnoreCase) != 0) ? 
                 currentDirectory.Substring(initialDirLength) : currentDirectory;

        foreach (var file in TryEnumerate(() =>
                 Directory.EnumerateFiles(currentDirectory, filePattern)))
        
            yield return returnRelativePaths ? file.Substring(initialDirLength) : file;
        

        foreach (var directory in TryEnumerate(() =>
                 Directory.EnumerateDirectories(currentDirectory, filePattern)))
        
            searchStack.Push(directory);
        
    


static void Main(string[] args)

    foreach (var result in FindFilesAndDirectories(@"c:\", true))
    
        Console.WriteLine(result);
    

【讨论】:

【参考方案3】:
public static void DirectorySearch(string dir)

    try
    
        foreach (string f in Directory.GetFiles(dir))
        
            Console.WriteLine(Path.GetFileName(f));
        
        foreach (string d in Directory.GetDirectories(dir))
        
            Console.WriteLine(Path.GetFileName(d));
            DirectorySearch(d);
        
    
    catch (System.Exception ex)
    
        Console.WriteLine(ex.Message);
    

注意:该函数只显示没有相对路径的名称。

【讨论】:

如果您可以对代码的作用添加一点解释,这将改善您的答案。 递归遍历目录并打印文件名或目录名。对于每个内部目录,它调用相同的函数。欲了解更多信息:***.com/questions/929276/…【参考方案4】:

这样你就可以在控制台运行时运行它们并选择子文件夹

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using data.Patcher; // The patcher XML
namespace PatchBuilder

class Program

    static void Main(string[] args)
    
        string patchDir;
        if (args.Length == 0)
        
            Console.WriteLine("Give the patch directory in argument");
            patchDir = Console.ReadLine();
        
        else
        
            patchDir = args[0];
        

        if (File.Exists(Path.Combine(patchDir, "patch.xml")))
            File.Delete(Path.Combine(patchDir, "patch.xml"));

        var files = Directory.EnumerateFiles(patchDir, "*", SearchOption.AllDirectories).OrderBy(p => p).ToList();

        foreach (var file in files.Where(file => file.StartsWith("patch\\Resources")).ToArray())
        
            files.Remove(file);
            files.Add(file);
        

        var tasks = new List<MetaFileEntry>();
        using (var md5Hasher = MD5.Create())
        
            for (int i = 0; i < files.Count; i++)
            
                var file = files[i];

                if ((File.GetAttributes(file) & FileAttributes.Hidden) != 0)
                    continue;

                var content = File.ReadAllBytes(file);
                var md5Hasher2 = MD5.Create();

                var task =
                    new MetaFileEntry
                    
                        LocalURL = GetRelativePath(file, patchDir + "\\"),
                        RelativeURL = GetRelativePath(file, patchDir + "\\"),
                        FileMD5 = Convert.ToBase64String(md5Hasher2.ComputeHash(content)),
                        FileSize = content.Length,
                    ;

                md5Hasher2.Dispose();

                var pathBytes = Encoding.UTF8.GetBytes(task.LocalURL.ToLower());
                md5Hasher.TransformBlock(pathBytes, 0, pathBytes.Length, pathBytes, 0);
                if (i == files.Count - 1)
                    md5Hasher.TransformFinalBlock(content, 0, content.Length);
                else
                    md5Hasher.TransformBlock(content, 0, content.Length, content, 0);

                tasks.Add(task);
                Console.WriteLine(@"Add " + task.RelativeURL);
            

            var patch = new MetaFile
            
                Tasks = tasks.ToArray(),
                FolderChecksum = BitConverter.ToString(md5Hasher.Hash).Replace("-", "").ToLower(),
            ;


            //XmlUtils.Serialize(Path.Combine(patchDir, "patch.xml"), patch);
            Console.WriteLine(@"Created Patch in 0 !", Path.Combine(patchDir, "patch.xml"));
        

        Console.Read();
    

    static string GetRelativePath(string fullPath, string relativeTo)
    
        var foldersSplitted = fullPath.Split(new[]  relativeTo.Replace("/", "\\").Replace("\\\\", "\\") , StringSplitOptions.RemoveEmptyEntries); // cut the source path and the "rest" of the path

        return foldersSplitted.Length > 0 ? foldersSplitted.Last() : ""; // return the "rest"
    


这是用于 XML 导出的补丁

using System.Xml.Serialization;

namespace data.Patcher

    public class MetaFile
    

        [XmlArray("Tasks")]
        public MetaFileEntry[] Tasks
        
            get;
            set;
        

        [XmlAttribute("checksum")]
        public string FolderChecksum
        
            get;
            set;
        
    

【讨论】:

【参考方案5】:

一些具有最大 lvl 的改进版本可以进入目录并选择排除文件夹:

using System;
using System.IO;

class MainClass 
  public static void Main (string[] args) 

    var dir = @"C:\directory\to\print";
    PrintDirectoryTree(dir, 2, new string[] "folder3");
  


  public static void PrintDirectoryTree(string directory, int lvl, string[] excludedFolders = null, string lvlSeperator = "")
  
    excludedFolders = excludedFolders ?? new string[0];

    foreach (string f in Directory.GetFiles(directory))
    
        Console.WriteLine(lvlSeperator+Path.GetFileName(f));
     

    foreach (string d in Directory.GetDirectories(directory))
    
        Console.WriteLine(lvlSeperator + "-" + Path.GetFileName(d));

        if(lvl > 0 && Array.IndexOf(excludedFolders, Path.GetFileName(d)) < 0)
        
          PrintDirectoryTree(d, lvl-1, excludedFolders, lvlSeperator+"  ");
        
    
  

输入目录:

-folder1
  file1.txt
  -folder2
    file2.txt
    -folder5
      file6.txt
  -folder3
    file3.txt
  -folder4
    file4.txt
    file5.txt

函数的输出(folder5 的内容因 lvl 限制而被排除,而 folder3 的内容因在 excludeFolders 数组中而被排除):

-folder1
  file1.txt
  -folder2
    file2.txt
    -folder5
  -folder3
  -folder4
    file4.txt
    file5.txt

【讨论】:

【参考方案6】:

创建字符串列表

    public static List<string> htmlFiles = new List<string>();

 private void Form1_Load(object sender, EventArgs e)
        

     HTMLFiles.AddRange(Directory.GetFiles(@"C:\DataBase", "*.txt"));
            foreach (var item in HTMLFiles)
            
                MessageBox.Show(item);
            


【讨论】:

这没有得到子目录。【参考方案7】:

有点简单和缓慢但有效! 如果您不提供文件路径,则基本上使用“fixPath”,这只是示例....您可以搜索所需的正确文件类型,当我选择列表名称时我犯了一个错误,因为“temporaryFileList 是搜索的文件列表所以继续……“errorList”不言自明

 static public void Search(string path, string fileType, List<string> temporaryFileList, List<string> errorList)
    

        List<string> temporaryDirectories = new List<string>();

        //string fix = @"C:\Users\" + Environment.UserName + @"\";
        string fix = @"C:\";
        string folders = "";
        //Alap útvonal megadása 
        if (path.Length != 0)
         folders = path; 
        else  path = fix; 

        int j = 0;
        int equals = 0;
        bool end = true;

        do
        

            equals = j;
            int k = 0;

            try
            

                int foldersNumber = 
                Directory.GetDirectories(folders).Count();
                int fileNumber = Directory.GetFiles(folders).Count();

                if ((foldersNumber != 0 || fileNumber != 0) && equals == j)
                

                    for (int i = k; k < 
                    Directory.GetDirectories(folders).Length;)
                    

             temporaryDirectories.Add(Directory.GetDirectories(folders)[k]);
                        k++;
                    

                    if (temporaryDirectories.Count == j)
                    
                        end = false;
                        break;
                    
                    foreach (string files in Directory.GetFiles(folders))
                    
                        if (files != string.Empty)
                        
                            if (fileType.Length == 0)
                            
                                temporaryDirectories.Add(files);
                            
                            else
                            

                                if (files.Contains(fileType))
                                
                                    temporaryDirectories.Add(files);

                                
                            
                        
                        else
                        
                            break;
                        
                    

                

                equals++;

                for (int i = j; i < temporaryDirectories.Count;)
                
                    folders = temporaryDirectories[i];
                    j++;
                    break;
                

            
            catch (Exception ex)
            
                errorList.Add(folders);

                for (int i = j; i < temporaryDirectories.Count;)
                
                    folders = temporaryDirectories[i];
                    j++;
                    break;
                
            
         while (end);
    

【讨论】:

【参考方案8】:

您可以使用返回句柄的 FindFirstFile,然后递归调用调用 FindNextFile 的函数。这是一个很好的方法,因为引用的结构将填充各种数据,例如替代名称、lastTmeCreated、修改、属性等

但是当你使用.net框架时,你将不得不进入非托管区域。

【讨论】:

【参考方案9】:

Directory.GetFileSystemEntries 存在于 .NET 4.0+ 中并返回文件和目录。像这样称呼它:

string[] entries = Directory.GetFileSystemEntries(path, "*", SearchOption.AllDirectories);

请注意,它无法处理列出您无权访问的子目录内容的尝试 (UnauthorizedAccessException),但它可能足以满足您的需求。

【讨论】:

这是迄今为止最好的答案。它在一行代码中获取所有文件和文件夹,其他代码都没有。 我得到了一些隐藏文件夹,例如:“F:\$RECYCLE.BIN”、“F:\System Volume Information”。如何忽略这些文件夹(仅获取文件和文件夹显示在视图中) @YenDang 在路径上调用File.GetAttributes - MSDN 示例代码专门演示隐藏文件【参考方案10】:
string[] allfiles = Directory.GetFiles("path/to/dir", "*.*", SearchOption.AllDirectories);

*.* 是匹配文件的模式

如果还需要目录,您可以这样:

 foreach (var file in allfiles)
     FileInfo info = new FileInfo(file);
 // Do something with the Folder or just add them to a list via nameoflist.add();
 

【讨论】:

真的不行...Lsit&lt;&gt;class? GetFiles 返回什么?那些也被请求的目录名称呢? GetFiles 方法返回一个字符串数组。 实际上......你是对的......我两天前正在学习 Qt 并且有点误会 这可能有效,但通常会失败并出现 UnauthorizedAccessException。如何只搜索它可以访问的目录? 这意味着在你的系统中这个应用没有足够的权限【参考方案11】:

我将以下代码与一个有 2 个按钮的表单一起使用,一个用于退出,另一个用于启动。文件夹浏览器对话框和保存文件对话框。下面列出了代码,适用于我的系统 Windows10 (64):

using System;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Directory_List


    public partial class Form1 : Form
    
        public string MyPath = "";
        public string MyFileName = "";
        public string str = "";

        public Form1()
        
            InitializeComponent();
            
        private void cmdQuit_Click(object sender, EventArgs e)
        
            Application.Exit();
            
        private void cmdGetDirectory_Click(object sender, EventArgs e)
        
            folderBrowserDialog1.ShowDialog();
            MyPath = folderBrowserDialog1.SelectedPath;    
            saveFileDialog1.ShowDialog();
            MyFileName = saveFileDialog1.FileName;    
            str = "Folder = " + MyPath + "\r\n\r\n\r\n";    
            DirectorySearch(MyPath);    
            var result = MessageBox.Show("Directory saved to Disk!", "", MessageBoxButtons.OK);
                Application.Exit();    
            
        public void DirectorySearch(string dir)
        
                try
            
                foreach (string f in Directory.GetFiles(dir))
                
                    str = str + dir + "\\" + (Path.GetFileName(f)) + "\r\n";
                    
                foreach (string d in Directory.GetDirectories(dir, "*"))
                

                    DirectorySearch(d);
                
                        System.IO.File.WriteAllText(MyFileName, str);

            
            catch (System.Exception ex)
            
                Console.WriteLine(ex.Message);
            
        
    

【讨论】:

【参考方案12】:

以下示例以最快(非并行化)方式列出目录树中处理异常的文件和子文件夹。使用 SearchOption.AllDirectories 使用 Directory.EnumerateDirectories 枚举所有目录会更快,但如果遇到 UnauthorizedAccessException 或 PathTooLongException,此方法将失败。

使用通用 Stack 集合类型,它是后进先出 (LIFO) 堆栈,不使用递归。从https://msdn.microsoft.com/en-us/library/bb513869.aspx,允许您枚举所有子目录和文件并有效地处理这些异常。

    public class StackBasedIteration

    static void Main(string[] args)
    
        // Specify the starting folder on the command line, or in 
        // Visual Studio in the Project > Properties > Debug pane.
        TraverseTree(args[0]);

        Console.WriteLine("Press any key");
        Console.ReadKey();
    

    public static void TraverseTree(string root)
    
        // Data structure to hold names of subfolders to be
        // examined for files.
        Stack<string> dirs = new Stack<string>(20);

        if (!System.IO.Directory.Exists(root))
        
            throw new ArgumentException();
        
        dirs.Push(root);

        while (dirs.Count > 0)
        
            string currentDir = dirs.Pop();
            string[] subDirs;
            try
            
                subDirs = System.IO.Directory.EnumerateDirectories(currentDir); //TopDirectoryOnly
            
            // An UnauthorizedAccessException exception will be thrown if we do not have
            // discovery permission on a folder or file. It may or may not be acceptable 
            // to ignore the exception and continue enumerating the remaining files and 
            // folders. It is also possible (but unlikely) that a DirectoryNotFound exception 
            // will be raised. This will happen if currentDir has been deleted by
            // another application or thread after our call to Directory.Exists. The 
            // choice of which exceptions to catch depends entirely on the specific task 
            // you are intending to perform and also on how much you know with certainty 
            // about the systems on which this code will run.
            catch (UnauthorizedAccessException e)
                                
                Console.WriteLine(e.Message);
                continue;
            
            catch (System.IO.DirectoryNotFoundException e)
            
                Console.WriteLine(e.Message);
                continue;
            

            string[] files = null;
            try
            
                files = System.IO.Directory.EnumerateFiles(currentDir);
            

            catch (UnauthorizedAccessException e)
            

                Console.WriteLine(e.Message);
                continue;
            

            catch (System.IO.DirectoryNotFoundException e)
            
                Console.WriteLine(e.Message);
                continue;
            
            // Perform the required action on each file here.
            // Modify this block to perform your required task.
            foreach (string file in files)
            
                try
                
                    // Perform whatever action is required in your scenario.
                    System.IO.FileInfo fi = new System.IO.FileInfo(file);
                    Console.WriteLine("0: 1, 2", fi.Name, fi.Length, fi.CreationTime);
                
                catch (System.IO.FileNotFoundException e)
                
                    // If file was deleted by a separate application
                    //  or thread since the call to TraverseTree()
                    // then just continue.
                    Console.WriteLine(e.Message);
                    continue;
                
                catch (UnauthorizedAccessException e)
                                    
                    Console.WriteLine(e.Message);
                    continue;
                
            

            // Push the subdirectories onto the stack for traversal.
            // This could also be done before handing the files.
            foreach (string str in subDirs)
                dirs.Push(str);
        
    

【讨论】:

使用 Tasks 处理大量文件和目录? msdn.microsoft.com/en-us/library/ff477033(v=vs.110).aspx 是上述解决方案的并行线程版本,使用堆栈集合并且速度更快。【参考方案13】:

逻辑有序的方式:

using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;

namespace DirLister

class Program

    public static void Main(string[] args)
    
        //with reflection I get the directory from where this program is running, thus listing all files from there and all subdirectories
        string[] st = FindFileDir(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location));
        using ( StreamWriter sw = new StreamWriter("listing.txt", false ) )
        
            foreach(string s in st)
            
                //I write what I found in a text file
                sw.WriteLine(s);
            
        
    

    private static string[] FindFileDir(string beginpath)
    
        List<string> findlist = new List<string>();

        /* I begin a recursion, following the order:
         * - Insert all the files in the current directory with the recursion
         * - Insert all subdirectories in the list and rebegin the recursion from there until the end
         */
        RecurseFind( beginpath, findlist );

        return findlist.ToArray();
    

    private static void RecurseFind( string path, List<string> list )
    
        string[] fl = Directory.GetFiles(path);
        string[] dl = Directory.GetDirectories(path);
        if ( fl.Length>0 || dl.Length>0 )
        
            //I begin with the files, and store all of them in the list
            foreach(string s in fl)
                list.Add(s);
            //I then add the directory and recurse that directory, the process will repeat until there are no more files and directories to recurse
            foreach(string s in dl)
            
                list.Add(s);
                RecurseFind(s, list);
            
        
    


【讨论】:

您能否提供解释或内联 cmets,您的代码是做什么的? 当然,完成了,但它应该是不言自明的,它是一个简单的循环递归遍历所有目录和文件【参考方案14】:

如果您无权访问目录树中的子文件夹,Directory.GetFiles 会停止并引发异常,从而导致接收字符串 [] 中出现空值。

在这里,看到这个答案 https://***.com/a/38959208/6310707

它在循环内管理异常并继续工作直到遍历整个文件夹。

【讨论】:

【参考方案15】:
using System.IO;
using System.Text;
string[] filePaths = Directory.GetFiles(@"path", "*.*", SearchOption.AllDirectories);

【讨论】:

您的答案不会为已经存在的投票最多的答案添加任何新内容。 这也是错误的,因为这不返回任何目录(如问题所指定),只返回实际文件。【参考方案16】:

恐怕GetFiles 方法返回文件列表而不是目录。问题中的列表提示我结果也应该包括文件夹。如果您想要更多自定义列表,您可以尝试递归调用GetFilesGetDirectories。试试这个:

List<string> AllFiles = new List<string>();
void ParsePath(string path)

    string[] SubDirs = Directory.GetDirectories(path);
    AllFiles.AddRange(SubDirs);
    AllFiles.AddRange(Directory.GetFiles(path));
    foreach (string subdir in SubDirs)
        ParsePath(subdir);

提示:如果您需要检查任何特定属性,可以使用 FileInfoDirectoryInfo 类。

【讨论】:

【参考方案17】:

使用GetDirectoriesGetFiles 方法获取文件夹和文件。

使用SearchOptionAllDirectories 也可以获取子文件夹中的文件夹和文件。

【讨论】:

使用Substring 将名字的左边部分截掉。 :) @Lucero 您如何以及为什么要这样做? Path 提供更可靠的方法。 @Gusdor 随意建议使用Path 删除路径的固定左侧部分的更合适的方式,例如`C:` 在给出的例子中。 @Lucero 我的评论措辞不佳。 'Use substring' 并没有告诉我很多,我不得不陷入 linqpad 以获得一个不错的解决方案。例如,参数是什么?你打算用path.SubString(2) 天真地删除驱动器号和冒号吗?如果目录是网络共享怎么办?我建议Path 作为一种可靠的方法,因为它可以在这个领域提供大量的好东西。在这种情况下,您可以写filePath.Substring(Path.GetPathRoot(filePath).Length)。是的,这使用了 Substring,因为它是最简洁的。

以上是关于列出一个目录+子目录中的所有文件和目录的主要内容,如果未能解决你的问题,请参考以下文章

递归法列出目录中的所有文件

使用 Python 从 FTP 列出所有子目录中的所有文件

PHP列出目录中的所有文件[重复]

使用 jcifs 列出所有文件和目录

如何列出另一个订阅中的另一个 Azure Data Lake gen2 存储帐户中的所有文件和子目录

列出一个目录中的所有文件PHP [重复]