檔案同步工具需要以黑名單方式排除特定路徑及檔案型別,這回我想要高級一點,學習 .gitignore 或 .csproj 的 Include 屬性,支援 Include="Images\**\*jpgs\*.*" 這種萬用字元彈性路徑樣式。(** 代表零到多層子目錄)

經過研究,這種檔案路徑萬用字元語法的術語叫 Globbing,被廣泛應用在 Unix Bash Shell、Git .gitignore 過濾路徑及檔案。心想,既然 csproj 認得,.NET 應該有現成程式庫可用不需要自己寫,關鍵字對了,很快找到答案:File globbing in .NET

.NET Platform Extensions 是微軟官方開發的 API 集合,提供 DI、Cache、Logging、Configuration 等開發常用程式庫,但沒有隨 .NET SDK 安裝,專案再透過 NuGet 下載取得。其中有個 Matcher 類別,能依事先定義的檔案路徑規則(有包含及排除兩種規則)搜尋目錄,列出符合的檔案。(註:支援 .NET6/.NET Standard 2.0/.NET Framework 4.6.2)

先整理可用的萬用字元範例,才知怎麼應用它:

比對樣式符合對象
*.txt所有 .txt 副檔名
*.*所有有附檔案名的檔案
*最上層目錄的所有檔案
.*以 '.' 起始的檔案
*word*檔案包含 'word'
readme.*主檔名 'readme',附檔名不限
styles/*.css目錄 'styles/' 下的所有 .css 檔
scripts/*/*'scripts/' 及第一層子目錄下所有檔案
images*/*以 'images' 起始目錄下的所有檔案
**/*所有子目錄的所有檔案
dir/**/*'dir/'下所有子目錄的所有檔案

Matcher 的使用方式很簡單,new Matcher() 建立物件,呼叫 AddInclude()、AddExclude() 加入要包含或排除的樣式字串(另有 AddIncludePatterns() 及 AddExcludePatterns() 擴充方法可傳入 IEnumerable<string> 一次加入多筆),接著呼叫 GetResultsInFullPath() 擴充方法搜尋指定目錄,便能得到符合條件的檔案路徑清單。(註:若需要取得相對路徑、萬用字元以下相對路徑... 則可呼叫原始 API - Execute())

學會原理,做個範例來演練,我建了一個測試用的目錄結構如下:

建立 .NET 6 Console 專案,dotnet add package Microsoft.Extensions.FileSystemGlobbing 參照程式庫,用以下程式進行多組測試。(花了點功夫寫了方便測試及顯示結果的函式,大家可自行修改,驗證想測的比對樣式)

using Microsoft.Extensions.FileSystemGlobbing;
using Microsoft.Extensions.FileSystemGlobbing.Abstractions;

var matcher = new Matcher();

var testDir = "D:\\demo";

var incPatterns = new List<string>();
Action<string> addIncludePattern = (p) => {
    incPatterns.Add(p);
    matcher.AddInclude(p);
};
var excPatterns = new List<string>();
Action<string> addExcludePattern = (p) => {
    excPatterns.Add(p);
    matcher.AddExclude(p);
};
Action dir = () =>
{
    Console.ForegroundColor = ConsoleColor.Cyan;
    Console.WriteLine(new string('=', 32));
    Console.ForegroundColor = ConsoleColor.Yellow;
    Console.WriteLine($"Including: {string.Join(", ", incPatterns.ToArray())}");
    Console.ForegroundColor = ConsoleColor.Magenta;
    if (excPatterns.Any())
        Console.WriteLine($"Excluding: {string.Join(", ", excPatterns.ToArray())}");
    Console.ForegroundColor = ConsoleColor.Cyan;
    Console.WriteLine("[Results]");
    Console.ForegroundColor = ConsoleColor.White;
    foreach (var file in matcher.GetResultsInFullPath(testDir))
        Console.WriteLine(file);
    Console.WriteLine();
};
Action reset = () => {
    matcher = new Matcher();
    incPatterns.Clear();
    excPatterns.Clear();
};

addIncludePattern("*.md");
dir();
addIncludePattern("*/*.md");
dir();
reset();
addIncludePattern("**/*.md");
dir();
addIncludePattern("*/north/*.txt");
dir();
reset();
addIncludePattern("**/*");
dir();
addExcludePattern("*/north/*.txt");
addExcludePattern("*/*.md");
dir();

測試結果:

開發工具箱再收獲好用工具一只。

Introduce to using Matcher class to search directory by customized including and excluding rules.


Comments

# by 小黑

好物,謝黑哥

Post a comment