Partilhar via


Globo de ficheiros em .NET

Neste artigo, você aprenderá a usar o globbing de arquivos com o 📦 Microsoft.Extensions.FileSystemGlobbing pacote NuGet. Um glob é um termo usado para definir padrões para nomes de arquivos e diretórios correspondentes com base em curingas. Globbing é o ato de definir um ou mais padrões de glob e obter arquivos através de correspondências que podem ser inclusivas ou exclusivas.

Padrões

Para corresponder arquivos no sistema de arquivos com base em padrões definidos pelo usuário, comece instanciando um Matcher objeto. A Matcher pode ser instanciado sem parâmetros, ou com um System.StringComparison parâmetro, que é usado internamente para comparar padrões com nomes de arquivos. O Matcher expõe os seguintes métodos aditivos:

Ambos os métodos AddExclude e AddInclude podem ser chamados qualquer número de vezes, para adicionar vários padrões de nomes de ficheiros a excluir ou incluir nos resultados. Depois de instanciar um Matcher e adicionar padrões, ele é usado para avaliar correspondências de um diretório inicial com o Matcher.Execute método.

Métodos de extensão

O Matcher objeto tem vários métodos de extensão.

Exclusões múltiplas

Para adicionar vários padrões de exclusão, você pode usar:

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

Como alternativa, você pode usar o MatcherExtensions.AddExcludePatterns(Matcher, IEnumerable<String>[]) para adicionar vários padrões de exclusão em uma única chamada:

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

Este método de extensão itera por todos os padrões fornecidos, chamando AddExclude por ti.

Inclusões múltiplas

Para adicionar vários padrões de inclusão, você pode usar:

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

Como alternativa, você pode usar o MatcherExtensions.AddIncludePatterns(Matcher, IEnumerable<String>[]) para adicionar vários padrões de inclusão em uma única chamada:

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

Este método de extensão itera por todos os padrões fornecidos, chamando AddInclude por ti.

Obter todos os arquivos correspondentes

Para obter todos os ficheiros correspondentes, tem de chamar Matcher.Execute(DirectoryInfoBase) direta ou indiretamente. Para chamá-lo diretamente, você precisa de um diretório de pesquisa:

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.

O código C# anterior:

Nota

O DirectoryInfoWrapper tipo é definido no Microsoft.Extensions.FileSystemGlobbing.Abstractions namespace e o DirectoryInfo tipo é definido no System.IO namespace. Para evitar diretivas desnecessárias using , você pode usar os métodos de extensão fornecidos.

Há outro método de extensão que produz um IEnumerable<string> que representa os ficheiros correspondentes.

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.

O código C# anterior:

  • Instancia um objeto Matcher.
  • Chama AddIncludePatterns(Matcher, IEnumerable<String>[]) para incluir vários padrões de nomes de ficheiro.
  • Declara e define o valor do diretório de pesquisa.
  • Chama GetResultsInFullPath dado o valor de searchDirectory para produzir todos os arquivos correspondentes como um IEnumerable<string>.

Sobrecarga de correspondências

O PatternMatchingResult objeto representa uma coleção de FilePatternMatch instâncias e expõe um boolean valor que indica se o resultado tem correspondências—PatternMatchingResult.HasMatches.

Com uma instância Matcher, pode chamar qualquer uma das várias Match sobrecargas para obter um resultado de correspondência de padrões. Os Match métodos invertem a responsabilidade do chamador de fornecer um arquivo ou uma coleção de arquivos para avaliar as correspondências. Em outras palavras, o chamador é responsável por passar o arquivo para corresponder.

Importante

Ao usar qualquer uma das Match sobrecargas, não há operações de E/S do sistema de arquivos envolvidas. Todo o globbing de ficheiros é feito na memória com os padrões de inclusão e exclusão da instância matcher. Os parâmetros das Match sobrecargas não precisam ser caminhos totalmente qualificados. O diretório atual (Directory.GetCurrentDirectory()) é usado quando não especificado.

Para corresponder a um único ficheiro:

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

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

O código C# anterior:

  • Corresponde a qualquer arquivo com a extensão de arquivo .md , em uma profundidade de diretório arbitrária.
  • Se existir um arquivo chamado file.md em um subdiretório do diretório atual:
    • result.HasMatches seria true.
    • e result.Files teria uma partida.

As sobrecargas adicionais Match funcionam de forma semelhante.

Avaliação ordenada de inclusão/exclusão

Por padrão, o correspondente avalia todos os padrões de inclusão primeiro e, em seguida, aplica todos os padrões de exclusão, independentemente da ordem em que você os adicionou. Isso significa que você não pode reincluir arquivos que foram excluídos anteriormente.

A partir da versão 10 do 📦 pacote Microsoft.Extensions.FileSystemGlobbing, você pode optar pela avaliação ordenada , onde as inclusões e exclusões são processadas exatamente na sequência em que foram adicionadas:

using Microsoft.Extensions.FileSystemGlobbing;

// Preserve the order of patterns when matching.
Matcher matcher = new(preserveFilterOrder: true);

matcher.AddInclude("**/*");                // include everything
matcher.AddExclude("logs/**/*");           // exclude logs
matcher.AddInclude("logs/important/**/*"); // re-include important logs

var result = matcher.Execute(new DirectoryInfoWrapper(new DirectoryInfo(root)));
foreach (var file in result.Files)
{
    Console.WriteLine(file.Path);
}

Neste modo, os padrões são aplicados um após o outro:

  • **/* adiciona todos os arquivos.
  • logs/**/* remove tudo de logs/.
  • logs/important/**/* reintegra apenas os ficheiros em logs/important/.

O código existente que usa o construtor padrão continuará a ser executado com o comportamento original "all includes, then all excludes".

Formatos de padrão

Os padrões especificados nos AddExclude métodos e AddInclude podem usar os seguintes formatos para corresponder a vários arquivos ou diretórios.

  • Diretório exato ou nome do arquivo

    • some-file.txt
    • path/to/file.txt
  • Curingas * em nomes de arquivos e diretórios que representam zero a muitos caracteres, não incluindo caracteres separadores.

    valor Descrição
    *.txt Todos os arquivos com extensão de arquivo .txt .
    *.* Todos os ficheiros com uma extensão.
    * Todos os ficheiros no diretório de nível superior.
    .* Nomes de ficheiros que comecem por '.'.
    *word* Todos os ficheiros com 'word' no nome do ficheiro.
    readme.* Todos os arquivos chamados 'readme' com qualquer extensão de arquivo.
    styles/*.css Todos os arquivos com extensão '.css' no diretório 'styles/'.
    scripts/*/* Todos os ficheiros em 'scripts/' ou num nível de subdiretório sob 'scripts/'.
    images*/* Todos os arquivos em uma pasta com nome que é ou começa com 'imagens'.
  • Profundidade de diretório arbitrária (/**/).

    valor Descrição
    **/* Todos os arquivos em qualquer subdiretório.
    dir/ Todos os arquivos em qualquer subdiretório em 'dir/'.
    dir/**/* Todos os arquivos em qualquer subdiretório em 'dir/'.
  • Caminhos relativos.

    Para fazer a correspondência entre todos os arquivos em um diretório chamado "compartilhado" no nível irmão e o diretório base fornecido ao Matcher.Execute(DirectoryInfoBase), use ../shared/*.

Exemplos

Considere o seguinte diretório de exemplo e cada arquivo dentro de sua pasta correspondente.

📁 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

Gorjeta

Algumas extensões de arquivo estão em maiúsculas, enquanto outras estão em minúsculas. Por padrão, StringComparer.OrdinalIgnoreCase é usado. Para especificar um comportamento de comparação de cadeia de caracteres diferente, use o Matcher.Matcher(StringComparison) construtor.

Para obter todos os arquivos de markdown, onde a extensão do arquivo é .md ou .mtext, independentemente do caso do caractere:

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

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

A execução do aplicativo produziria resultados semelhantes aos seguintes:

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

Para obter quaisquer arquivos em um diretório de ativos em uma profundidade arbitrária:

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

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

A execução do aplicativo produziria resultados semelhantes aos seguintes:

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

Para obter quaisquer ficheiros onde o nome do diretório contenha a palavra filho a uma profundidade arbitrária e as extensões de ficheiro não são .md, .text ou .mtext:

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

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

A execução do aplicativo produziria resultados semelhantes aos seguintes:

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

Consulte também