【问题标题】:Beginner-friendly method to get list of all files and directories获取所有文件和目录列表的初学者友好方法
【发布时间】:2009-10-10 03:39:15
【问题描述】:

使用 .NET 3.0,我得到了下面的方法,它可以正确返回指定目录的所有文件和目录(以及子目录)的集合。如果可能的话,我想把它简化为只使用我很舒服的结构。具体来说,我不清楚的地方如下:

1. IEnumerable<FileSystemInfo>: I'd like to return List<FileSystemInfo> instead
2. Stack<FileSystemInfo>: I'd list to use List<FileSystemInfo> instead.
3. yield return: I've never used this before

.

public static IEnumerable<FileSystemInfo> GetAllFilesAndDirectories ( string dir ) {

    DirectoryInfo dirInfo = new DirectoryInfo( dir );
    Stack<FileSystemInfo> stack = new Stack<FileSystemInfo>();

    stack.Push( dirInfo );
    while ( dirInfo != null || stack.Count > 0 ) {
        FileSystemInfo fileSystemInfo = stack.Pop();
        DirectoryInfo subDirectoryInfo = fileSystemInfo as DirectoryInfo;
        if ( subDirectoryInfo != null ) {
            yield return subDirectoryInfo;
            foreach ( FileSystemInfo fsi in subDirectoryInfo.GetFileSystemInfos() ) {
                stack.Push( fsi );
            }
            dirInfo = subDirectoryInfo;
        } else {
            yield return fileSystemInfo;
            dirInfo = null;
        }
    }

}

.

可以说我应该对上面的代码感到满意,但这不是我今天的目标。

提前致谢

【问题讨论】:

  • 在问题中添加了“使用 .NET 3.0”。

标签: c# directory


【解决方案1】:

这是我能想到的最短路径:

static List<FileSystemInfo> GetAllFilesAndDirectories(string dir)
{
    DirectoryInfo dirInfo = new DirectoryInfo(dir);            
    List<FileSystemInfo> allFilesAndDirectories = new List<FileSystemInfo>();

    allFilesAndDirectories.AddRange(dirInfo.GetFiles("*", SearchOption.AllDirectories));
    allFilesAndDirectories.AddRange(dirInfo.GetDirectories("*", SearchOption.AllDirectories));

    return allFilesAndDirectories;
}

它将返回从给定路径开始的所有级别的所有文件和目录的列表。它返回它们的顺序是所有文件,然后是所有目录。

【讨论】:

    【解决方案2】:

    我相信您正在寻找现有的方法 GetFileSystemInfos(string, SearchOptions)。如果将 AllDirectories 指定为 SearchOptions 值,它将递归搜索传入的文件夹。

    例如:

    public static List<FileSystemInfo> GetAllFilesAndDirectories ( string dir ) {
      DirectoryInfo info = new DirectoryInfo(dir);
      FileSystemInfo[] all = info.GetFileSystemInfos("*", SearchOptions.AllDirectories);
      return new List<FileSystemInfo>(all);
    }
    

    如果你想把它写出来,虽然你可以做以下事情

    public static List<FileSystemInfo> GetAllFilesAndDirectories ( string dir ) {
      int i = 0; 
      List<DirectoryInfo> toProcess = new List<DirectoryInfo>();
      List<FileSystemInfo> list = new List<FileSystemInfo>();
      toProcess.Add(new DirectoryInfo(dir));
      while ( i < toProcess.Count ) { 
        DirectoryInfo curDir = toProcess[i];
        foreach ( FileSystemInfo curFile in curDir.GetFileSystemInfos() ) {
          list.Add(curFile);
          DirectoryInfo maybe = curFile as DirectoryInfo;
          if ( maybe != null ) {
            toProcess.Add(maybe);
          }
        i++;
      }
      return list;
    }
    
      FileSystemInfo[] all = info.GetFileSystemInfos("*", SearchOptions.AllDirectories);
      return new List<FileSystemInfo>(all);
    }
    

    【讨论】:

    • @bobbymcr,根据文档msdn.microsoft.com/en-us/library/ms143448(VS.100).aspx,AllDirectories 是一个递归搜索函数
    • 那行不通。 OP 显然希望从给定路径开始获取所有子文件夹中的所有文件和目录。这将只返回第一级。请注意,没有可以接受 SearchOptions 枚举的 GetFileSystemInfos 重载。
    • 糟糕,更正,在 .NET 4.0 之前无法做到这一点。所以最终还是有可能的……
    • 感谢您的回答。尝试“如果你想把它写得很远”的代码,它似乎不包括子目录及其内容。
    【解决方案3】:
        public List<Object> GetFilesAndDirectories(string path)
        {
            List<Object> lst = new List<Object>();
            string[] dirs = null;
    
            try
            {
                dirs = Directory.GetDirectories(path);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
    
            foreach (string d in dirs)
            {
                string[] files = null;
    
                try
                {
                    files = Directory.GetFiles(d);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                }
    
                foreach (string f in files)
                {
                    lst.Add(f);
                }
    
                lst.Add(d);
    
                lst.AddRange(GetFilesAndDirectories(d));
            }
    
            return lst;
        }
    
    
    List<Object> stuff = GetFilesAndDirectories(someRoot);
    

    【讨论】:

    • 我要指出的是,最好不要只记录catch { } 异常,最好至少记录它们。
    • 当然。此外,这是使用列表的通用对象类型编写的,以防您想要存储实际的文件/目录对象而不是字符串表示形式。定制以满足您的需求。
    • 如果您希望您的 catch 语句从字面上“不停止”该方法,那么您需要在 foreach 循环中使用 try/catch 块。然后,如果您发现异常,您将继续循环并查看目录中的其他文件。
    • "Empty catch" 通常是错误的做法。这会抓住任何东西。只需捕获该方法实际上可以抛出的异常。在这种情况下,它可能是 IOException(读取磁盘时出错,或者目录在列出之前被删除),UnauthorizedAccessException(对于用户无法列出的目录)。
    • @Kirk Broadhurst - 确实。更改帖子以反映。
    【解决方案4】:

    您曾特别要求“将其简化”。我认为其他两个答案非常好,但这是另一种方法,可以使用更基本、更易于理解的初级代码。

    http://support.microsoft.com/kb/303974

    编辑

    我知道这不是 3.0,但它仍然是经过尝试、测试且易于理解的方式。

    【讨论】:

      【解决方案5】:

      如果你想要一个“适合初学者的方法”,我可以建议bobbymcr method

      但是,如果你想保持你的代码结构,我复制下面我在your following question 中发布的代码:

      static IEnumerable<FileSystemInfo> GetAllFilesAndDirectories(string path)
      {
          string currentDirectory = "";
          string[] files = Directory.GetFiles( // skip empty subfolders
              path, "*.*", SearchOption.AllDirectories);
          foreach (string file in files)
          {
              if(currentDirectory != Path.GetDirectoryName(file))
              {
                  // First time in this directory: return it
                  currentDirectory = Path.GetDirectoryName(file);
                  yield return new DirectoryInfo(currentDirectory);
              }
      
              yield return new FileInfo(file);
          }
      }
      

      【讨论】:

        【解决方案6】:

        我认为从代码可读性的角度来看,最好的办法是编写一个递归函数。递归函数是一个调用自身的函数,直到它到达不需要调用任何其他函数的地步。

        为了说明,n的阶乘,写成n!并定义为数量 1 x 2 x 3 x ... x n(其中 n 是正整数)可以很容易地以递归方式定义,如下所示。

        public int factorial(int n)
        {
            if (n < 0)
            {
                throw new Exception("A factorial cannot be calculated for negative integers.");
            }
        
            if (n == 0 || n == 1)
            {
                // end condition, where we do not need to make a recursive call anymore
                return 1;
            }
            else
            {
                // recursive call
                return n * factorial(n - 1);
            }
        }
        

        注意:0!和1!被定义为 1。

        同样,枚举给定路径下的所有文件和文件夹的方法也可以递归定义。这是因为文件和文件夹具有递归结构。

        因此,可以使用如下方法:

        public static List<FileSystemInfo> GetAllFilesAndFolders(string folder)
        {
            // NOTE : We are performing some basic sanity checking
            // on the method's formal parameters here
            if (string.IsNullOrEmpty(folder))
            {
                throw new ArgumentException("An empty string is not a valid path.", "folder");
            }
            if (!Directory.Exists(folder))
            {
                throw new ArgumentException("The string must be an existing path.", "folder");
            }
        
            List<FileSystemInfo> fileSystemInfos = new List<FileSystemInfo>();
        
            try
            {
                foreach (string filePath in Directory.GetFiles(folder, "*.*"))
                {
                    // NOTE : We will add a FileSystemInfo object for each file found
                    fileSystemInfos.Add(new FileInfo(filePath));
                }
            }
            catch
            {
                // NOTE : We are swallowing all exceptions here
                // Ideally they should be surfaced, and at least logged somewhere
                // Most of these will be security/permissions related, i.e.,
                // the Directory.GetFiles method will throw an exception if it
                // does not have security privileges to enumerate files in a folder.
            }
            try
            {
                foreach (string folderPath in Directory.GetDirectories(folder, "*"))
                {
                    // NOTE : We will add a FileSystemInfo object for each directory found
                    fileSystemInfos.Add(new DirectoryInfo(folderPath));
        
                    // NOTE : We will also add all FileSystemInfo objects found under
                    // each directory we find
                    fileSystemInfos.AddRange(GetAllFilesAndFolders(folderPath));
                }
            }
            catch
            {
                // NOTE : We are swallowing all exceptions here
                // Ideally they should be surfaced, and at least logged somewhere
                // Most of these will be security/permissions related, i.e.,
                // the Directory.GetDirectories method will throw an exception if it
                // does not have security privileges to enumerate files in a folder.
            }
        
            return fileSystemInfos;
        }
        

        需要注意的是,此方法将“遍历”文件夹下的整个目录结构,并且在“遍历”整个层次结构之前不会返回。因此,如果要找到的对象很多,可能需要很长时间才能返回。

        另外需要注意的是,这个方法的可读性可以通过使用 Lambda 表达式和扩展方法进一步提高。

        注意:使用 Directory.GetFiles 和 Directory.GetDirectories 递归子文件夹的问题在于,如果抛出任何异常(例如,与安全权限相关),该方法将不会返回任何内容,而手动递归则允许处理那些异常并且仍然​​得到一组文件。

        【讨论】:

          猜你喜欢
          • 2016-07-04
          • 1970-01-01
          • 2010-12-01
          • 2014-07-10
          • 2010-11-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-04-26
          相关资源
          最近更新 更多