Подстановка имен файлов в .NET

В этой статье вы узнаете, как использовать подстановку имен файлов с пакетом NuGet Microsoft.Extensions.FileSystemGlobbing. Стандартная маска — термин, используемый для определения шаблонов сопоставления имен файлов и каталогов на основе подстановочных знаков. Подстановка имен — это процесс определения одного или нескольких шаблонов стандартных масок и получения файлов, которые совпадают или не совпадают с этими шаблонами.

Шаблоны

Чтобы сопоставить файлы в файловой системе на основе определяемых пользователем шаблонов, начните с создания экземпляра объекта Matcher. Можно создать экземпляр Matcher без параметров или с параметром System.StringComparison, который используется внутренне для сравнения шаблонов с именами файлов. Matcher предоставляет следующие аддитивные методы:

И метод AddExclude, и AddInclude можно вызывать любое количество раз, чтобы добавлять различные шаблоны имен файлов, исключаемые из результатов или включаемые в них. После создания экземпляра Matcher и добавления шаблонов, он используется для вычисления совпадений из начального каталога с помощью метода Matcher.Execute.

Методы расширения

Объект Matcher имеет несколько методов расширения.

Множественные исключения

Чтобы добавить несколько шаблонов исключения, можно использовать:

Matcher matcher = new();
matcher.AddExclude("*.txt");
matcher.AddExclude("*.asciidoc");
matcher.AddExclude("*.md");

Кроме того, можно использовать MatcherExtensions.AddExcludePatterns(Matcher, IEnumerable<String>[]) для добавления нескольких шаблонов исключения в один вызов:

Matcher matcher = new();
matcher.AddExcludePatterns(new [] { "*.txt", "*.asciidoc", "*.md" });

Этот метод расширения выполняет итерацию всех предоставленных шаблонов, вызывающих AddExclude от вашего имени.

Множественные включения

Чтобы добавить несколько шаблонов включения, можно использовать:

Matcher matcher = new();
matcher.AddInclude("*.txt");
matcher.AddInclude("*.asciidoc");
matcher.AddInclude("*.md");

Кроме того, можно использовать MatcherExtensions.AddIncludePatterns(Matcher, IEnumerable<String>[]) для добавления нескольких шаблонов включения в один вызов:

Matcher matcher = new();
matcher.AddIncludePatterns(new[] { "*.txt", "*.asciidoc", "*.md" });

Этот метод расширения выполняет итерацию всех предоставленных шаблонов, вызывающих AddInclude от вашего имени.

Получение всех соответствующих файлов

Чтобы получить все соответствующие файлы, необходимо вызвать Matcher.Execute(DirectoryInfoBase), напрямую или косвенно. Для непосредственного вызова вам потребуется каталог поиска:

Matcher matcher = new();
matcher.AddIncludePatterns(new[] { "*.txt", "*.asciidoc", "*.md" });

string searchDirectory = "../starting-folder/";

PatternMatchingResult result = matcher.Execute(
    new DirectoryInfoWrapper(
        new DirectoryInfo(searchDirectory)));

// Use result.HasMatches and results.Files.
// The files in the results object are file paths relative to the search directory.

В приведенном выше коде C#:

  • Создает объект Matcher.
  • Вызывает AddIncludePatterns(Matcher, IEnumerable<String>[]), чтобы добавить несколько шаблонов имен файлов для включения.
  • Объявляет и присваивает значение каталога поиска.
  • Создает экземпляр DirectoryInfo из заданного searchDirectory.
  • Создает экземпляр DirectoryInfoWrapper из DirectoryInfo, оболочкой которого он является.
  • Вызывает Execute, которому передан экземпляр DirectoryInfoWrapper для получения объекта PatternMatchingResult.

Примечание.

Тип DirectoryInfoWrapper определен в пространстве имен Microsoft.Extensions.FileSystemGlobbing.Abstractions, а тип DirectoryInfo определен в пространстве имен System.IO. Чтобы избежать ненужных инструкций using, можно использовать предоставленные методы расширения.

Существует другой метод расширения, который возвращает IEnumerable<string>, представляющий соответствующие файлы:

Matcher matcher = new();
matcher.AddIncludePatterns(new[] { "*.txt", "*.asciidoc", "*.md" });

string searchDirectory = "../starting-folder/";

IEnumerable<string> matchingFiles = matcher.GetResultsInFullPath(searchDirectory);

// Use matchingFiles if there are any found.
// The files in this collection are fully qualified file system paths.

В приведенном выше коде C#:

  • Создает объект Matcher.
  • Вызывает AddIncludePatterns(Matcher, IEnumerable<String>[]), чтобы добавить несколько шаблонов имен файлов для включения.
  • Объявляет и присваивает значение каталога поиска.
  • Вызывает GetResultsInFullPath с заданным значением searchDirectory для получения всех соответствующих файлов в виде IEnumerable<string>.

Перегрузки совпадений

Объект PatternMatchingResult представляет коллекцию экземпляров FilePatternMatch и предоставляет значение, указывающее, совпадает ли результат с результатомboolean.PatternMatchingResult.HasMatches

С помощью экземпляра Matcher можно вызвать любую из различных перегрузок Match, чтобы получить результат сопоставления шаблона. Методы Match перекладывают на вызывающий объект ответственность за предоставление файла или коллекции файлов, которые должны оцениваться на предмет совпадений. Иными словами, вызывающий объект отвечает за передачу файла для сопоставления.

Внимание

При использовании любой из перегрузок Match операции ввода-вывода файловой системы не используются. Вся подстановка имен файлов выполняется в памяти с шаблонами включения и исключения экземпляра matcher. Параметры перегрузок Match не обязательно должны быть полными путями. Если ничего не указано, используется текущий каталог (Directory.GetCurrentDirectory()).

Для сопоставления в одном файле:

Matcher matcher = new();
matcher.AddInclude("**/*.md");

PatternMatchingResult result = matcher.Match("file.md");

В приведенном выше коде C#:

  • Соответствует любому файлу с расширением .md на произвольной глубине каталога.
  • Если файл с именем file.md существует в подкаталоге из текущего каталога:
    • result.HasMatches будет true.
    • А result.Files будет иметь одно совпадение.

Дополнительные перегрузки Match работают аналогичным образом.

Форматы шаблонов

Шаблоны, указанные в методах AddExclude и AddIncludeмогут использовать следующие форматы для сопоставления нескольких файлов или каталогов.

  • Точное имя каталога или файла

    • some-file.txt
    • path/to/file.txt
  • Подстановочные знаки * в именах файлов и каталогов, представляющих ноль и многие символы, не включая символы-разделители.

    значение Описание
    *.txt Все файлы с расширением .txt.
    *.* Все файлы с расширением.
    * Все файлы в каталоге верхнего уровня.
    .* Имена файлов, начинающиеся с ".".
    *word* Все файлы с "word" в имени файла.
    readme.* Все файлы с именем "readme" и любым расширением файла.
    styles/*.css Все файлы с расширением ".css" в каталоге "styles/".
    scripts/*/* Все файлы в каталоге "scripts/" или на один уровень вложенного каталога ниже "scripts/".
    images*/* Все файлы в папке с именем "images" или именем, начинающимся с "images".
  • Произвольная глубина каталога (/**/).

    значение Описание
    **/* Все файлы в любом подкаталоге.
    dir/ Все файлы в любом подкаталоге каталога "dir/".
    dir/**/* Все файлы в любом подкаталоге каталога "dir/".
  • Относительные пути.

    Чтобы сопоставить все файлы в каталоге с именем "shared" на уровне родственного элемента базового каталога, предоставленного Matcher.Execute(DirectoryInfoBase), используйте ../shared/*.

Примеры

Рассмотрим следующий пример каталога и каждый файл в его соответствующей папке.

📁 parent
│    file.md
│    README.md
│
└───📁 child
    │    file.MD
    │    index.js
    │    more.md
    │    sample.mtext
    │
    ├───📁 assets
    │        image.png
    │        image.svg
    │
    └───📁 grandchild
             file.md
             style.css
             sub.text

Совет

Некоторые расширения файлов находятся в верхнем регистре, а другие — в нижнем регистре. По умолчанию используется StringComparer.OrdinalIgnoreCase. Чтобы указать другое поведение сравнения строк, используйте конструктор Matcher.Matcher(StringComparison).

Для получения всех файлов разметки, где расширение файла .md или .mtext, независимо от регистра символов:

Matcher matcher = new();
matcher.AddIncludePatterns(new[] { "**/*.md", "**/*.mtext" });

foreach (string file in matcher.GetResultsInFullPath("parent"))
{
    Console.WriteLine(file);
}

При запуске приложения выводятся результаты, аналогичные приведенным ниже:

C:\app\parent\file.md
C:\app\parent\README.md
C:\app\parent\child\file.MD
C:\app\parent\child\more.md
C:\app\parent\child\sample.mtext
C:\app\parent\child\grandchild\file.md

Чтобы получить любые файлы в каталоге assets с произвольной глубиной:

Matcher matcher = new();
matcher.AddInclude("**/assets/**/*");

foreach (string file in matcher.GetResultsInFullPath("parent"))
{
    Console.WriteLine(file);
}

При запуске приложения выводятся результаты, аналогичные приведенным ниже:

C:\app\parent\child\assets\image.png
C:\app\parent\child\assets\image.svg

Для получения файлов, у которых имя каталога содержит слово child, с произвольной глубиной и расширениями которых не являются .md, .text или .mtext:

Matcher matcher = new();
matcher.AddInclude("**/*child/**/*");
matcher.AddExcludePatterns(
    new[]
    {
        "**/*.md", "**/*.text", "**/*.mtext"
    });

foreach (string file in matcher.GetResultsInFullPath("parent"))
{
    Console.WriteLine(file);
}

При запуске приложения выводятся результаты, аналогичные приведенным ниже:

C:\app\parent\child\index.js
C:\app\parent\child\assets\image.png
C:\app\parent\child\assets\image.svg
C:\app\parent\child\grandchild\style.css

См. также