LoginSignup
2
0

More than 3 years have passed since last update.

PathMatcher::matchesでIllegalArgumentExceptionが発生する

Last updated at Posted at 2019-09-14

事象

いきなり個人的な事情で申し訳ないのですが、一連のファイルやディレクトリに対して、globを使ってフィルタリングしたいという場合、Files::newDirectoryStream(Path, String)を利用してきました。というより、その方法しか知りませんでした。

このAPIでは第2引数にglobを指定します。以下がその例になります。

var dir = Paths.get(".");
try (var paths = Files.newDirectoryStream(dir, "**.py")) {
    for (var path : paths) {
        doSomething(path);
    }
} catch (IOException e) {
    e.printStackTrace();
}

正直なところDirectoryStreamは使いにくいAPIで、とくに「java.util.Streamにつなげづらい」というのが、個人的にはもっともつらい。要するに「globによるフィルタリングをStream処理に組み込みたい」わけです。そこで、いろいろと調べてまわったところ、java.nio.file.PathMatcherを利用すればよいということが判明。

var dir = Paths.get(".");
var matcher = FileSystems.getDefault().getPathMatcher("**.py");
Files.walk(dir).filter(matcher::matches).forEach(path -> doSomething(path));

さっそくこれを実行したところ、以下のようにIllegalArgumentExceptionが発生し、想定通りに動作しませんでした。


Exception in thread "main" java.lang.IllegalArgumentException
    at java.base/sun.nio.fs.WindowsFileSystem.getPathMatcher(WindowsFileSystem.java:262)
    at Main.main(Main.java:19)

原因と対処

今回は「JavaDocをちゃんと読みましょう」案件でした…。FileSystem::getPathMatcher(String)のJavaDocには次の通り記述されています。

syntaxAndPattern パラメータは、構文とパターンを識別し、次の形式をとります。

syntax:pattern

ここでの ':' はそれ自体を表します。
FileSystem 実装では、「glob」および「regex」構文をサポートしますが、その他をサポートすることもできます。構文コンポーネントの値は大文字小文字に関係なく比較されます。

今回のようにglobパターンを利用したい場合はglob:**.pyというような書き方をする必要があるということです。それを使って上記の例を書き換えたものが以下になり、これを実行するとIllegalArgumentExceptionが発生しなくなりました。

var dir = Paths.get(".");
var matcher = FileSystems.getDefault().getPathMatcher("glob:**.py");
Files.walk(dir).filter(matcher::matches).forEach(path -> doSomething(path));
2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0