【问题标题】:How can I loop over all the files in all directories and get the types of the files only?如何遍历所有目录中的所有文件并仅获取文件的类型?
【发布时间】:2016-06-25 06:07:25
【问题描述】:

如果我没记错的话,在这种方法中它是在文件中搜索。 因此,当我输入 searchTerm 例如“Form1”时,它找到了 46 个文件。

但现在我想更改没有 searchTerm 的方法,这样它会遍历所有文件,但最后我想获取所有文件类型的列表。如果有相同的重复项,请不要将它们添加到列表中,所以最后我会得到一个包含文件类型项目的列表,例如:cs、txt、xml,这样我就会知道有哪些文件类型。

IEnumerable<string> SearchAccessibleFiles(string root, string searchTerm)
        {
            var files = new List<string>();

            foreach (var file in Directory.EnumerateFiles(root).Where(m => m.Contains(searchTerm)))
            {
                files.Add(file);
            }
            foreach (var subDir in Directory.EnumerateDirectories(root))
            {
                try
                {
                    files.AddRange(SearchAccessibleFiles(subDir, searchTerm));
                }
                catch (UnauthorizedAccessException ex)
                {
                    // ...
                }
            }

            return files;
        }

问题是,如果我只是制作 GetFiles 并且根目录是 c:\,那么当它到达 Windows 10 中的目录时,它将停止并且不会获取任何文件:文档和设置

Directory.GetFiles(textBox3.Text, "*.*", SearchOption.AllDirectories).ToList();

由于我没有找到解决 Directory.GetFiles 的方法,因此我正在尝试使用递归方法。

【问题讨论】:

    标签: c# .net winforms


    【解决方案1】:

    您可以使用extension = Path.GetExtension(fileName); 获取文件扩展名,并在文件列表中使用.Distinct() 删除重复项,如下所示:

    IEnumerable<string> SearchAccessibleFiles(string root, string searchTerm)
        {
            var files = new List<string>();
    
            foreach (var file in Directory.EnumerateFiles(root).Where(m => m.Contains(searchTerm)))
            {
                string extension = Path.GetExtension(file);
                files.Add(extension);
            }
            foreach (var subDir in Directory.EnumerateDirectories(root))
            {
                try
                {
                    files.AddRange(SearchAccessibleFiles(subDir, searchTerm));
                }
                catch (UnauthorizedAccessException ex)
                {
                    // ...
                }
            }
            return files.Distinct().ToList();
        }
    

    您可以简单地删除 .Where(m =&gt; m.Contains(searchTerm)) 部分以进行搜索而不使用搜索词。

    编辑 如果您不想使用.Distict() 并想随时随地检查重复项,您可以尝试以下方法:

    IEnumerable<string> SearchAccessibleFilesNoDistinct(string root, List<string> files)
    {
        if(files == null)
           files = new List<string>();
    
        foreach (var file in Directory.EnumerateFiles(root))
        {
            string extension = Path.GetExtension(file);
            if(!files.Containes(extension))
               files.Add(extension);
        }
        foreach (var subDir in Directory.EnumerateDirectories(root))
        {
            try
            {
                SearchAccessibleFilesNoDistinct(subDir, files);
            }
            catch (UnauthorizedAccessException ex)
            {
                // ...
            }
        }
        return files;
    }
    

    第一次通话是这样的:

    var extensionsList = SearchAccessibleFilesNoDistinct("rootAddress",null);
    

    你可以看到我通过递归方法传递了文件列表,通过这种方法,我们在所有递归调用中都有相同的文件列表,所以应该可以解决问题,请记住,在递归调用中不需要获取返回的列表因为我们已经有相同的列表,但最后我们可以使用返回的列表以供进一步使用。 希望对你有帮助

    【讨论】:

    • 工作良好。我添加了一个问题,因此它不会添加重复的扩展名: if (!files.Contains(extension)) 就在行 files.Add(extension); 之前但我最后仍然看到重复的扩展名。为什么它不断添加重复项?
    • @מנימנחם,那是因为您正在递归调用 SearchAccessibleFiles,每次调用 SearchAccessibleFiles 时都会创建一个新的 files 列表实例,您将添加此列表 usnig @ 987654331@ 作为回报。所以if (!files.Contains(extension)) 只处理该目录中的重复文件,而不是上层目录或子目录。
    • @מנימנחם,你知道你错在哪里了吗?
    • 我明白了,但不知道如何在代码中做到这一点。我不能将 List 实例从函数中取出。不确定。
    【解决方案2】:

    问题可以分解为几个部分:

    (1) 递归枚举所有可访问目录
    (2) 枚举多个目录文件
    (3) 获取不同的文件扩展名

    请注意,只有 (3) 是特定的,(1) 和 (2) 是通用的,可用于其他处理(如您的 SearchAccessibleFiles 等)。所以让我们分别解决它们:

    (1)递归枚举所有可访问目录:

    这又可以分为两部分:

    (A) 递归枚举通用树结构
    (B) 可访问目录树的上述特化

    对于 (A) 我个人使用我对 How to flatten tree via LINQ? 的回答中的帮助方法和类似方法:

    public static class TreeUtils
    {
        public static IEnumerable<T> Expand<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> elementSelector)
        {
            var stack = new Stack<IEnumerator<T>>();
            var e = source.GetEnumerator();
            try
            {
                while (true)
                {
                    while (e.MoveNext())
                    {
                        var item = e.Current;
                        yield return item;
                        var elements = elementSelector(item);
                        if (elements == null) continue;
                        stack.Push(e);
                        e = elements.GetEnumerator();
                    }
                    if (stack.Count == 0) break;
                    e.Dispose();
                    e = stack.Pop();
                }
            }
            finally
            {
                e.Dispose();
                while (stack.Count != 0) stack.Pop().Dispose();
            }
        }
    }
    

    这是我们案例的专业化:

    public static partial class DirectoryUtils
    {
        public static IEnumerable<DirectoryInfo> EnumerateAccessibleDirectories(string path, bool all = false)
        {
            var filter = Func((IEnumerable<DirectoryInfo> source) => 
                source.Select(di =>
                {
                    try { return new { Info = di, Children = di.EnumerateDirectories() }; }
                    catch (UnauthorizedAccessException) { return null; }
                })
                .Where(e => e != null));
    
            var items = filter(Enumerable.Repeat(new DirectoryInfo(path), 1));
            if (all)
                items = items.Expand(e => filter(e.Children));
            else
                items = items.Concat(items.SelectMany(e => filter(e.Children)));
            return items.Select(e => e.Info);
        }
    
        static Func<T, TResult> Func<T, TResult>(Func<T, TResult> func) { return func; }
    }
    

    (2)枚举多个目录文件:

    消除重复代码的简单扩展方法:

    partial class DirectoryUtils
    {
        public static IEnumerable<FileInfo> EnumerateAccessibleFiles(string path, bool allDirectories = false)
        {
            return EnumerateAccessibleDirectories(path, allDirectories).EnumerateFiles();
        }
    
        public static IEnumerable<FileInfo> EnumerateFiles(this IEnumerable<DirectoryInfo> source)
        {
            return source.SelectMany(di => di.EnumerateFiles());
        }
    }
    

    (3) 获取不同的文件扩展名:

    使用上述帮助程序,这是一个简单的 LINQ 查询:

    var result = DirectoryUtils.EnumerateAccessibleFiles(rootPath, true)
        .Select(file => file.Extension).Distinct()
        .ToList();
    

    最后,为了比较,以下是使用相同帮助器时原始方法的外观:

    IEnumerable<string> SearchAccessibleFiles(string root, string searchTerm)
    {
        return DirectoryUtils.EnumerateAccessibleFiles(rootPath, true)
            .Where(file => file.FullName.Contains(searchTerm))
            .Select(file => file.FullName);
    }
    

    如果搜索词不应该包含目录信息,您可以将过滤条件更改为file.Name.Contains(searchTerm)

    【讨论】:

      猜你喜欢
      • 2015-03-05
      • 1970-01-01
      • 2016-08-01
      • 2018-10-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多