多个通配符目录/文件搜索,用于C#.net中的任意目录结构 [英] Multiple wildcard directory/file search for arbitrary directory structure in C# .net

查看:345
本文介绍了多个通配符目录/文件搜索,用于C#.net中的任意目录结构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在C#和.net 4.0中的Visual Studio 2012中构建Windows应用程序。



该程序的功能之一是搜索符合条件的所有文件。



搜索条件在运行时未知;





可能的搜索条件可以包括以下内容:


  1. 确切路径


    • C:\temp\directory1\directory2\someFile.txt


  2. 路径,文件名中带有通配符:


    • C:\temp\directory1\ \directory2 *。*


  3. 文件名,路径中带有通配符:


    • C:\temp * \directory * \someFile.txt


  4. 带通配符的文件名和路径:


    • C:\temp\ * \ * \ *。*


  5. 所有上述内容,具有任意目录结构:


    • C:\temp\dir * 1\ \dir * \anotherdir\ * \another * \file * .txt

    • C:\te * \ * \someFile.txt

    • C:\temp\ * tory1\dire * 2\ * \ * \ * \ * \ *。*


我尝试使用 Directory.EnumerateFiles

  IEnumerable< string> matchingFilePaths = System.IO.Directory.EnumerateFiles(@ C:\,selectedItemPath [0],System.IO.SearchOption.AllDirectories); 

但是,这仅适用于上述情况2。尝试将 Directory.EnumerateFiles 与文件夹名称中的通配符一起使用会导致非法字符豁免。



我希望.net中有一个内联代码,可以用来进行此文件搜索。在运行时通配符的数量和目录结构的深度是未知的,可以想象,搜索可能必须深入一百个文件夹,每个文件夹都包含未知数量的通配符。 (这是问题的症结)。尽量避免疯狂地嵌套for循环。



我阅读了,但这似乎不适用于任意文件夹结构。

我已经回答了您自己的问题,我想我会把它发布给其他可能会发现它并且不想使用Powershell的人。所有这些文件都是延迟加载的,因此在您具有大型文件系统并匹配大量文件的情况下,其性能将是最佳的。



示例用法:

 字符串模式= @ C:\Users\ * \Source\Repos\ * \ * .cs; 
foreach(在GetAllMatchingPaths(pattern)中的变量)
Console.WriteLine(st);

解决方案:

 公共静态IEnumerable< string> GetAllMatchingPaths(字符串模式)
{
字符分隔符= Path.DirectorySeparatorChar;
string [] parts = pattern.Split(separator);

if(parts [0] .Contains('*')|| parts [0] .Contains('?'))
throw new ArgumentException(路径根不得包含通配符,nameof(部分));

返回GetAllMatchingPathsInternal(String.Join(separator.ToString(),parts.Skip(1)),parts [0]);
}

私有静态IEnumerable< string> GetAllMatchingPathsInternal(字符串模式,字符串根)
{
字符分隔符= Path.DirectorySeparatorChar;
string [] parts = pattern.Split(separator);

for(int i = 0; i< parts.Length; i ++)
{
//如果路径的这部分是通配符,需要扩展
if(parts [i] .Contains('*')|| parts [i] .Contains('?'))
{
//创建一个指向当前通配符的绝对路径并检查如果存在
var组合=根+分隔符+ String.Join(separator.ToString(),parts.Take(i));
if(!Directory.Exists(combined))
返回新字符串[0];

if(i == parts.Length-1)//如果这是路径的结尾(文件名)
{
return Directory.EnumerateFiles(combined, parts [i],SearchOption.TopDirectoryOnly);
}
else //如果它在路径的中间(目录名)
{
var directory = Directory.EnumerateDirectories(combined,parts [i],SearchOption .TopDirectoryOnly);
var路径=目录.SelectMany(dir =>
GetAllMatchingPathsInternal(String.Join(separator.ToString(),parts.Skip(i + 1)),dir));
返回路径;
}
}
}

//如果模式以文件名
中的通配符结尾的绝对路径结尾var absolute = root +分隔符+字符串.Join(separator.ToString(),parts);
if(File.Exists(absolute))
return new [] {absolute};

返回新字符串[0];
}

PS::它将与目录不匹配,仅文件,但您可以根据需要轻松地对其进行修改。


I am building a Windows application in Visual Studio 2012 in C# and .net 4.0.

One of the functions of the program is to search for all files that meet a given search criteria, which usually (but doesn't always) include wildcards.

The search criteria is unknown at run time; it is imported from an excel spreadsheet.

Possible search criteria can include the following:

  1. Exact path
    • "C:\temp\directory1\directory2\someFile.txt"
  2. Path, with wildcards in the filename:
    • "C:\temp\directory1\directory2*.*"
  3. Filename, with wildcards in the path:
    • "C:\temp*\directory*\someFile.txt"
  4. Filename and path with wildcards:
    • "C:\temp\*\*\*.*"
  5. All of the above, with arbitrary directory structure:
    • "C:\temp\dir*1\dir*\anotherdir\*\another*\file*.txt"
    • "C:\te*\*\someFile.txt"
    • "C:\temp\*tory1\dire*2\*\*\*\*\*.*"

I've attempted to use Directory.EnumerateFiles:

IEnumerable<string> matchingFilePaths = System.IO.Directory.EnumerateFiles(@"C:\", selectedItemPath[0], System.IO.SearchOption.AllDirectories);

However this only works with Case 2 above. Attempting to use Directory.EnumerateFiles with wildcards in the folder names causes an "Illegal Character" exemption.

I'm hoping there's a one-liner in .net I can use to do this file searching. The number of wildcards and the depth of the directory structure is unknown at run time, and it's conceivable that the search might have to go a hundred folders deep, with every folder containing an unknown number of wildcards. (This is the crux of the problem). Trying to avoid having an insane number of nested for loops as well.

I read the solutions here but this doesn't seem to work for an arbitrary folder structure.

解决方案

Since you've already answered your own question I figured I'd post my attempt at it for any others who might find this and don't want to use powershell. Its all lazily loaded so its performance will be optimal in the case where you have a large file system and are matching lots of files.

Sample Usage:

string pattern = @"C:\Users\*\Source\Repos\*\*.cs";
foreach (var st in GetAllMatchingPaths(pattern))
    Console.WriteLine(st);

Solution:

public static IEnumerable<string> GetAllMatchingPaths(string pattern)
{
    char separator = Path.DirectorySeparatorChar;
    string[] parts = pattern.Split(separator);

    if (parts[0].Contains('*') || parts[0].Contains('?'))
        throw new ArgumentException("path root must not have a wildcard", nameof(parts));

    return GetAllMatchingPathsInternal(String.Join(separator.ToString(), parts.Skip(1)), parts[0]);
}

private static IEnumerable<string> GetAllMatchingPathsInternal(string pattern, string root)
{
    char separator = Path.DirectorySeparatorChar;
    string[] parts = pattern.Split(separator);

    for (int i = 0; i < parts.Length; i++)
    {
        // if this part of the path is a wildcard that needs expanding
        if (parts[i].Contains('*') || parts[i].Contains('?'))
        {
            // create an absolute path up to the current wildcard and check if it exists
            var combined = root + separator + String.Join(separator.ToString(), parts.Take(i));
            if (!Directory.Exists(combined))
                return new string[0];

            if (i == parts.Length - 1) // if this is the end of the path (a file name)
            {
                return Directory.EnumerateFiles(combined, parts[i], SearchOption.TopDirectoryOnly);
            }
            else // if this is in the middle of the path (a directory name)
            {
                var directories = Directory.EnumerateDirectories(combined, parts[i], SearchOption.TopDirectoryOnly);
                var paths = directories.SelectMany(dir =>
                    GetAllMatchingPathsInternal(String.Join(separator.ToString(), parts.Skip(i + 1)), dir));
                return paths;
            }
        }
    }

    // if pattern ends in an absolute path with no wildcards in the filename
    var absolute = root + separator + String.Join(separator.ToString(), parts);
    if (File.Exists(absolute))
        return new[] { absolute };

    return new string[0];
}

PS: It won't match directories, only files, but you could easily modify that if desired.

这篇关于多个通配符目录/文件搜索,用于C#.net中的任意目录结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆