Globbing dei file in .NET
In questo articolo si apprenderà come usare i criteri GLOB per i file con il pacchetto NuGet Microsoft.Extensions.FileSystemGlobbing
. Il termine GLOB viene usato per definire i criteri per individuare corrispondenze di nomi di file e directory in base ai caratteri jolly. Globbing è il termine che si riferisce all'atto di definire uno o più criteri GLOB e restituire file da corrispondenze inclusive o esclusive.
Criteri
Per trovare le corrispondenze dei file nel file system in base a criteri definiti dall'utente, iniziare creando un'istanza di un oggetto Matcher. È possibile creare un'istanza di un oggetto Matcher
senza parametri o con un parametro System.StringComparison usato internamente per confrontare i criteri con i nomi di file. Matcher
espone i metodi aggiuntivi seguenti:
Entrambi i metodi AddExclude
e AddInclude
possono essere chiamati un numero qualsiasi di volte, per aggiungere vari criteri per i nomi di file da escludere o includere nei risultati. Dopo aver creato un'istanza di Matcher
e aver aggiunto i criteri, l'oggetto viene quindi usato per valutare le corrispondenze da una directory iniziale con il metodo Matcher.Execute.
Metodi di estensione
Per l'oggetto Matcher
sono disponibili diversi metodi di estensione.
Esclusioni multiple
Per aggiungere più criteri di esclusione, è possibile usare:
Matcher matcher = new();
matcher.AddExclude("*.txt");
matcher.AddExclude("*.asciidoc");
matcher.AddExclude("*.md");
In alternativa, è possibile usare MatcherExtensions.AddExcludePatterns(Matcher, IEnumerable<String>[]) per aggiungere più criteri di esclusione in una singola chiamata:
Matcher matcher = new();
matcher.AddExcludePatterns(new [] { "*.txt", "*.asciidoc", "*.md" });
Questo metodo di estensione esegue l'iterazione su tutti i criteri specificati che chiamano AddExclude per conto dell'utente.
Inclusioni multiple
Per aggiungere più criteri di inclusione, è possibile usare:
Matcher matcher = new();
matcher.AddInclude("*.txt");
matcher.AddInclude("*.asciidoc");
matcher.AddInclude("*.md");
In alternativa, è possibile usare MatcherExtensions.AddIncludePatterns(Matcher, IEnumerable<String>[]) per aggiungere più criteri di inclusione in una singola chiamata:
Matcher matcher = new();
matcher.AddIncludePatterns(new[] { "*.txt", "*.asciidoc", "*.md" });
Questo metodo di estensione esegue l'iterazione su tutti i criteri specificati che chiamano AddInclude per conto dell'utente.
Ottenere tutti i file corrispondenti
Per ottenere tutti i file corrispondenti, è necessario chiamare Matcher.Execute(DirectoryInfoBase) direttamente o indirettamente. Per la chiamata diretta, è necessaria una directory di ricerca:
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.
Il codice C# precedente:
- Crea un'istanza di un oggetto Matcher.
- Chiama AddIncludePatterns(Matcher, IEnumerable<String>[]) per aggiungere diversi criteri di nomi di file da includere.
- Dichiara e assegna il valore della directory di ricerca.
- Crea un'istanza di DirectoryInfo dalla
searchDirectory
specificata. - Crea un'istanza di DirectoryInfoWrapper dalla
DirectoryInfo
di cui esegue il wrapping. - Chiama
Execute
in base all'istanza diDirectoryInfoWrapper
per restituire un oggetto PatternMatchingResult.
Nota
Il tipo DirectoryInfoWrapper
viene definito nello spazio dei nomi Microsoft.Extensions.FileSystemGlobbing.Abstractions
e il tipo DirectoryInfo
viene definito nello spazio dei nomi System.IO
. Per evitare direttive non necessarie using
, è possibile usare i metodi di estensione forniti.
Esiste un altro metodo di estensione che restituisce un oggetto IEnumerable<string>
che rappresenta i file corrispondenti:
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.
Il codice C# precedente:
- Crea un'istanza di un oggetto Matcher.
- Chiama AddIncludePatterns(Matcher, IEnumerable<String>[]) per aggiungere diversi criteri di nomi di file da includere.
- Dichiara e assegna il valore della directory di ricerca.
- Chiama
GetResultsInFullPath
dato il valoresearchDirectory
per restituire tutti i file corrispondenti comeIEnumerable<string>
.
Overload delle corrispondenze
L'oggetto PatternMatchingResult rappresenta una raccolta di istanze di FilePatternMatch ed espone un valore boolean
che indica se il risultato include corrispondenze (PatternMatchingResult.HasMatches).
Con un'istanza di Matcher
è possibile chiamare uno dei vari overload di Match
per ottenere un risultato di corrispondenza dei criteri. I metodi Match
invertono la responsabilità ed è il chiamante a dover fornire un file o una raccolta di file in cui valutare le corrispondenze. In altre parole, il chiamante è responsabile del passaggio del file per cui valutare le corrispondenze.
Importante
L'uso di uno degli overload di Match
non implica operazioni di I/O del file system. Tutte le operazioni di globbing dei file vengono eseguite in memoria con i criteri di inclusione ed esclusione dell'istanza di matcher
. I parametri degli overload Match
non devono essere percorsi completi. Se non viene specificata una directory, viene usata quella corrente (Directory.GetCurrentDirectory()).
Per trovare una corrispondenza con un singolo file:
Matcher matcher = new();
matcher.AddInclude("**/*.md");
PatternMatchingResult result = matcher.Match("file.md");
Il codice C# precedente:
- Trova la corrispondenza con qualsiasi file con estensione md, con una profondità di directory arbitraria.
- Se esiste un file denominato file.md in una sottodirectory della directory corrente:
result.HasMatches
sarebbetrue
.- e
result.Files
avrebbe una sola corrispondenza.
Gli overload Match
aggiuntivi funzionano in modi simili.
Formati dei criteri
I criteri specificati nei metodi AddExclude
e AddInclude
possono usare i formati seguenti per trovare la corrispondenza con più file o directory.
Nome esatto di directory o file
some-file.txt
path/to/file.txt
Caratteri jolly
*
nei nomi di file e directory che rappresentano da zero a molti caratteri, esclusi i caratteri separatore.Valore Descrizione *.txt
Tutti i file con estensione txt. *.*
Tutti i file con un'estensione. *
Tutti i file nella directory di primo livello. .*
Nomi di file che iniziano con '.'. *word*
Tutti i file con 'word' nel nome. readme.*
Tutti i file denominati 'readme' con qualsiasi estensione. styles/*.css
Tutti i file con estensione '.css' nella directory 'styles/'. scripts/*/*
Tutti i file in 'scripts/' o in un livello di sottodirectory in 'scripts/'. images*/*
Tutti i file in una cartella con il nome 'images' o che inizia con 'images'. Profondità di directory arbitraria (
/**/
).Valore Descrizione **/*
Tutti i file in qualsiasi sottodirectory. dir/
Tutti i file in qualsiasi sottodirectory di 'dir/'. dir/**/*
Tutti i file in qualsiasi sottodirectory di 'dir/'. Percorsi relativi.
Per trovare tutti i file in una directory denominata "shared" allo stesso livello della directory di base specificata per Matcher.Execute(DirectoryInfoBase), usare
../shared/*
.
Esempi
Si consideri la directory di esempio seguente e ogni file all'interno della cartella corrispondente.
📁 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
Suggerimento
Alcune estensioni di file sono in lettere maiuscole, mentre altre sono in lettere minuscole. Per impostazione predefinita si usa StringComparer.OrdinalIgnoreCase. Per specificare un comportamento diverso per il confronto delle stringhe, usare il costruttore Matcher.Matcher(StringComparison).
Per ottenere tutti i file markdown, in cui l'estensione del file è .md o .mtext, indipendentemente dalla combinazione di maiuscole e minuscole:
Matcher matcher = new();
matcher.AddIncludePatterns(new[] { "**/*.md", "**/*.mtext" });
foreach (string file in matcher.GetResultsInFullPath("parent"))
{
Console.WriteLine(file);
}
L'esecuzione dell'applicazione restituisce risultati simili ai seguenti:
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
Per ottenere qualsiasi file in una directory asset con profondità arbitraria:
Matcher matcher = new();
matcher.AddInclude("**/assets/**/*");
foreach (string file in matcher.GetResultsInFullPath("parent"))
{
Console.WriteLine(file);
}
L'esecuzione dell'applicazione restituisce risultati simili ai seguenti:
C:\app\parent\child\assets\image.png
C:\app\parent\child\assets\image.svg
Per ottenere tutti i file in cui il nome della directory contiene la parola child con una profondità arbitraria e le estensioni di file non sono .md, .text o .mtext:
Matcher matcher = new();
matcher.AddInclude("**/*child/**/*");
matcher.AddExcludePatterns(
new[]
{
"**/*.md", "**/*.text", "**/*.mtext"
});
foreach (string file in matcher.GetResultsInFullPath("parent"))
{
Console.WriteLine(file);
}
L'esecuzione dell'applicazione restituisce risultati simili ai seguenti:
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