如何遍历所有目录中的所有文件并仅获取文件类型?

时间:2016-06-25 06:07:25

标签: c# .net winforms

在这种方法中,如果我没弄错的话,它会搜索文件内部。 所以当我输入searchTerm例如" Form1"它找到了46个文件。

但是现在我想在没有searchTerm的情况下更改方法,因此它将遍历所有文件,但最后我想得到所有文件类型的List。如果有相同的dupilcate不要将它们添加到List中,那么最后我会得到一个List,文件类型项目如: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中的目录时它将停止并且不会获得任何文件:Documents and设置

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

由于我没有找到解决Directory.GetFiles的方法来传递这个目录,我试图使用递归方法。

2 个答案:

答案 0 :(得分: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 => 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);

你可以看到我通过递归方法传递文件列表,通过这种方法我们有相同的文件列表,在所有递归调用中都应该这样做,请记住在递归调用中没有必要得到返回的列表已经有了相同的列表,但最后我们可以使用返回的列表进一步使用。 希望有所帮助

答案 1 :(得分:1)

问题可分为几个部分:

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