Apache Ant の DirectoryScanner について
仕事で使うツールを作成する過程で、ワイルド・カードを含むファイル・パスをパースして、ファイルを取得する手段が必要になりました。あれこれ検索をしたものの、結局AntのAPIを使用する方法がいちばん簡単なようでした(あまりスマートな方法でないかもしれませんが)。
調査の中で参照したAntのドキュメントを以下に訳出しておきます。原典はAnt 1.9.3のJavadoc、DirectoryScannerクラスのドキュメントです。原典を参照する場合、Antプロジェクトの公式サイトから、ドキュメントをダウンロードする必要があります。
* * *
DirectoryScannerクラス
ディレクトリを読み取り、検索条件にマッチするファイルやディレクトリ群を見つけるためクラスです。
検索条件は特定のセレクターとパターンとから構成されます。セレクターにより、検索対象に含めたいファイルを選択することができます〔訳注*1〕。選択されなかったファイルは検索結果に含まれません。パターンにより、ファイル名に基づきそれぞれのファイルを検索結果に含めるか、含めないかを決めることができます。
概念はシンプルです。指定されたディレクトリはその配下のすべてのファイルとディレクトリ群について再帰的に読み取られます。それぞれのファイル/ディレクトリは、包含/除外パターンによるファイル名に対するマッチング機能を提供するものも含む〔訳注*2〕、一群のセレクターと比較検証されます。包含パターンのリストやその他のファイル・セレクターのうちの少なくとも一つに該当し、かつ、除外パターンのリストのうちのいずれかに該当したり必須条件セレクターへのマッチに失敗したりしなかったものだけが、検索結果のファイル/ディレクトリの一覧に格納されます。
包含パターンの一覧が明示的に設定されていない場合、デフォルト値として”**”が使用されます。これはあらゆる対象にマッチするパターンです。除外パターンの一覧が設定されていない場合、デフォルト値として空の一覧が使用されます。つまりいかなる対象も除外されません。セレクターが設定されていない場合、何も適用されません〔訳注*3〕。
ファイル名パターンのマッチングは次のように行われます: まず対象のファイル名〔ファイルパス〕はパス・セグメントに分割されます。分割されたパス・セグメントの各々はディレクトリもしくはファイル名です。これらはFile.separator(UNIX環境下では’/’、Windows環境下では’\’)により区切られています。例えば、"abc/def/ghi/xyz.java" というファイル名は、"abc"、"def"、"ghi"、そして"xyz.java"というセグメントに分割されます。同じことがパターンに対しても実施されます。
続いて、ファイル名とパターンのセグメントが互いに比較検証されます。パターン内のセグメントで’**’が使用されている場合、当該セグメントは0個もしくは1個以上のファイル名セグメントにマッチします。
パターンやファイル名の先頭におけるFile.separatorの使用については特別な考慮がなされます: パターンがFile.separatorで始まる場合、ファイル名もまたFile.separatorで始まらねばなりません。パターンがFile.separatorで始まらない場合、ファイル名もまたFile.separatorで始まらないものでないといけません。この決まりに該当しないファイル名は結果から除外されます。
ファイル名セグメントとパターンのセグメントが比較検証されるにあたり、次の特別な文字が使用可能です:
- '*'は0個か1個以上の文字にマッチする。
- '?'は1個の文字にマッチする。
例:
- "**\*.class"というパターンは、ディレクトリ・ツリー内のあらゆる.classファイル/ディレクトリにマッチする。
- "test\a??.java"というパターンは、testというディレクトリの直下の、’a’で始まり任意の2文字が続いたあと”.java”という拡張子の付くファイル/ディレクトリにマッチする。
- "**"というパターンは、ディレクトリ・ツリー内のあらゆるファイル/ディレクトリにマッチする。
- "**\test\**\XYZ*"というパターンは、testという名前のディレクトリを親ディレクトリに持ち、"XYZ"という文字列で始まる名前を持つファイル/ディレクトリ("abc\test\def\ghi\XYZ123"のような)にマッチする。
必要に応じて、大文字と小文字の区別をなくして検索をすることもできます。デフォルトでは、大文字と小文字は区別されます。
使用例:
String[] includes = {"*\*\*.class"}; String[] excludes = {"modules\\\*\**"}; ds.setIncludes(includes); ds.setExcludes(excludes); ds.setBasedir(new File("test")); ds.setCaseSensitive(true); ds.scan(); System.out.println("FILES:"); String[] files = ds.getIncludedFiles(); for (int i = 0; i < files.length; i++) { System.out.println(files[i]); }
このコードは、testというディレクトリ配下のディレクトリ・ツリーのすべての.classファイルのうち、"modules"というディレクトリ配下のものを除いたものを読み取って返します〔訳注*4〕。
* * *
原典はAnt 1.9.3のJavadoc、DirectoryScannerクラスのドキュメントです。原典を参照する場合、Antプロジェクトの公式サイトから、ドキュメントをダウンロードする必要があります。
*1:セレクターは、個々のファイルやディレクトリについて、ベース・ディレクトリやファイル名、Fileオブジェクトの情報などから、当該ファイルを検索結果に含めるかどうかを判定するインターフェースです。以下の説明では、セレクターとパターンの概念上の関係が明確にされていませんが、セレクターの実装の1つがパターンである、ということのようです。また以下ではもっぱらパターンについて説明がなされている一方、セレクターについてはほとんど何も説明がなされません。
*2:「…も含む」とありますが、実際上DirectoryScannerを使用するほとんどのケースで、包含/除外パターン以外のセレクターを使用することはないでしょう。
*3:つまりセレクターによる選別処理は行われないということです。
*4:includes/excludesとして指定されているパターンの書式が間違っていますが、これはプロジェクトのドキュメントに掲載のママです。