Подстановка имен файлов в .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