【问题标题】: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

【问题讨论】:

标签: c# directory subdirectory getdirectories


【解决方案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);
          }
      }
      

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

      【讨论】:

      • 如果您可以对代码的作用添加一点解释,这将改善您的答案。
      • 递归遍历目录并打印文件名或目录名。对于每个内部目录,它调用相同的函数。欲了解更多信息:stackoverflow.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);
                        }
                    }
                }
                

                【讨论】:

                【解决方案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://stackoverflow.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,因为它是最简洁的。
                    猜你喜欢
                    • 2012-11-14
                    • 2011-03-01
                    • 1970-01-01
                    • 2017-05-01
                    • 1970-01-01
                    • 2016-01-16
                    • 2011-02-23
                    相关资源
                    最近更新 更多