Comodines de archivos en .NET

En este artículo, aprenderá a usar comodines de archivos con el paquete NuGet Microsoft.Extensions.FileSystemGlobbing. Un patrón global es un término que se usa para definir patrones a fin de buscar coincidencias de nombres de archivos y directorios en función de caracteres comodín. El uso de comodines consiste en definir uno o varios patrones globales y generar archivos a partir de coincidencias inclusivas o exclusivas.

Patrones

Para hacer coincidir los archivos del sistema de archivos en función de patrones definidos por el usuario, empiece por crear instancias de un objeto Matcher. Se puede crear una instancia de Matcher sin parámetros o con un parámetro System.StringComparison, que se usa internamente para comparar patrones con nombres de archivo. Matcher expone los métodos aditivos siguientes:

Se puede llamar a los métodos AddExclude y AddInclude cualquier número de veces, a fin de agregar varios patrones de nombre de archivo que excluir de los resultados o incluir en estos. Una vez que haya creado una instancia de Matcher y agregado patrones, se usará para evaluar las coincidencias de un directorio inicial con el método Matcher.Execute.

Métodos de extensión

El objeto Matcher tiene varios métodos de extensión.

Varias exclusiones

Para agregar varios patrones de exclusión, puede usar lo siguiente:

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

Como alternativa, puede usar MatcherExtensions.AddExcludePatterns(Matcher, IEnumerable<String>[]) para agregar varios patrones de exclusión en una sola llamada:

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

Este método de extensión itera por todos los patrones proporcionados y llama a AddExclude en su nombre.

Varias inclusiones

Para agregar varios patrones de inclusión, puede usar lo siguiente:

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

Como alternativa, puede usar MatcherExtensions.AddIncludePatterns(Matcher, IEnumerable<String>[]) para agregar varios patrones de inclusión en una sola llamada:

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

Este método de extensión itera por todos los patrones proporcionados y llama a AddInclude en su nombre.

Obtención de todos los archivos coincidentes

Para obtener todos los archivos coincidentes, tendrá que llamar a Matcher.Execute(DirectoryInfoBase) de forma directa o indirecta. Para llamar al objeto directamente, necesita un directorio de búsqueda:

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.

El código de C# anterior:

Nota

El tipo DirectoryInfoWrapper se define en el espacio de nombres Microsoft.Extensions.FileSystemGlobbing.Abstractions y el tipo DirectoryInfo, en el espacio de nombres System.IO. Para evitar instrucciones using innecesarias, puede usar los métodos de extensión proporcionados.

Hay otro método de extensión que devuelve una interfaz IEnumerable<string> que representa los archivos coincidentes:

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.

El código de C# anterior:

  • Crea instancias de un objeto Matcher.
  • Llama a AddIncludePatterns(Matcher, IEnumerable<String>[]) para agregar varios patrones de nombre de archivo que se van a incluir.
  • Declara y asigna el valor del directorio de búsqueda.
  • Llama a GetResultsInFullPath dado el valor searchDirectory para que genere todos los archivos coincidentes como IEnumerable<string>.

Coincidencia de sobrecargas

El objeto PatternMatchingResult representa una colección de instancias de FilePatternMatch y expone un valor boolean que indica si el resultado tiene coincidencias:PatternMatchingResult.HasMatches.

Con una instancia de Matcher, puede llamar a cualquiera de las distintas sobrecargas de Match para obtener un resultado de coincidencia de patrones. Los métodos Match invierten la responsabilidad del autor de la llamada de proporcionar un archivo o una colección de archivos para evaluar las coincidencias. Es decir, el autor de la llamada es responsable de pasar el archivo sobre el que realizar la coincidencia.

Importante

Cuando se usa cualquiera de las sobrecargas de Match, no hay ninguna E/S del sistema de archivos implicada. Todo el uso de comodines de archivos se realiza en memoria con los patrones de inclusión y exclusión de la instancia de matcher. Los parámetros de las sobrecargas de Match no tienen que ser rutas completas. Si no se especifica, se usa el directorio actual (Directory.GetCurrentDirectory()).

Para hacer coincidir con un único archivo:

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

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

El código de C# anterior:

  • Compara cualquier archivo con la extensión de archivo .md, en una profundidad de directorio arbitraria.
  • Si existe un archivo con el nombre file.md en un subdirectorio del directorio actual:
    • result.HasMatches sería true.
    • y result.Files tendría una coincidencia.

Las sobrecargas de Match adicionales funcionan de maneras similares.

Formatos de patrón

Los patrones especificados en los métodos AddExclude y AddInclude pueden usar los formatos siguientes para comparar varios archivos o directorios.

  • Nombre exacto del directorio o archivo

    • some-file.txt
    • path/to/file.txt
  • Caracteres comodín * en nombres de archivos y directorios que representan de cero a varios caracteres sin incluir caracteres separadores.

    Value Descripción
    *.txt Todos los archivos con la extensión de archivo .txt.
    *.* Todos los archivos con una extensión.
    * Todos los archivos del directorio de nivel superior.
    .* Nombres de archivo que comienzan por ".".
    *word* Todos los archivos con "word" en el nombre de archivo.
    readme.* Todos los archivos denominados "léame" con cualquier extensión de archivo.
    styles/*.css Todos los archivos con la extensión ".css" en el directorio "styles/".
    scripts/*/* Todos los archivos de "scripts/" o un nivel de subdirectorio debajo de "scripts/".
    images*/* Todos los archivos de una carpeta cuyo nombre sea o comience por "images".
  • Profundidad arbitraria de directorio (/**/).

    Value Descripción
    **/* Todos los archivos de cualquier subdirectorio.
    dir/ Todos los archivos de cualquier subdirectorio debajo de "dir/".
    dir/**/* Todos los archivos de cualquier subdirectorio debajo de "dir/".
  • Rutas relativas.

    Para comparar todos los archivos de un directorio denominado "shared" del mismo nivel con el directorio base proporcionado a Matcher.Execute(DirectoryInfoBase), use ../shared/*.

Ejemplos

Tenga en cuenta el directorio de ejemplo siguiente y cada archivo dentro de su carpeta correspondiente.

📁 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

Sugerencia

Algunas extensiones de archivo están en mayúsculas, mientras que otras están en minúsculas. De forma predeterminada, se usa StringComparer.OrdinalIgnoreCase. Para especificar otro comportamiento de comparación de cadenas use el constructor Matcher.Matcher(StringComparison).

Para obtener todos los archivos Markdown, donde la extensión de archivo es .md o .mtext, independientemente del uso de mayúsculas y minúsculas:

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

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

La ejecución de la aplicación generaría una salida similar a la siguiente:

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 obtener los archivos de un directorio assets a una profundidad arbitraria:

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

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

La ejecución de la aplicación generaría una salida similar a la siguiente:

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

Para obtener los archivos en los que el nombre del directorio contiene la palabra child (secundario) a una profundidad arbitraria y las extensiones de archivo no son .md, .text ni .mtext:

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

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

La ejecución de la aplicación generaría una salida similar a la siguiente:

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 también