最近 Java SE 7 が正式リリースされたので、遅ればせながら API や言語使用の変更などをチラチラとチェック。 で、とりあえず身に着けておいた方が良さそうなのは I/O 周りのことかなぁと思ったので、API をあれこれ試してみることに。 記事の題名に反して、「仕様の哲学」みたいなことには触れませぬ*1。
シリーズ目次
- Path インターフェース, Paths クラス
- Files クラス 〜概要〜
- Files クラスのメソッド 〜ファイル、ディレクトリの作成〜
- Files クラスのメソッド 〜ファイル、ディレクトリの操作〜
- Files クラスのメソッド 〜ファイル内容の読み書き〜
- Files クラスのメソッド 〜ファイル、ディレクトリの属性〜
- Files クラスのメソッド 〜続・ファイル、ディレクトリの属性〜
- Files クラスのメソッド 〜ディレクトリの内容を走査〜
- Files クラスのメソッド 〜ディレクトリの階層を走査〜
- Files クラスのメソッド 〜ディレクトリの階層を Stream で走査〜
- Files クラスのメソッド ~MIME Type を調べる~
- ファイルシステム関連の型 FileSystem, FileSystems, FileStore
- Files クラスのメソッド ~続々・ファイル、ディレクトリの属性~
参考 URL
- The Java Tutorials 「File I/O (Featuring NIO.2)」
- API Document 「Package java.nio.file」
java.nio.file パッケージ
今までの Java バージョンでも既に java.nio パッケージは存在してましたが、あまり使われているのを見たことがないのが正直なところ。 しかーし、Java SE 7 では java.nio.file パッケージが追加されて、ファイルやパスの操作ができるようになったのでかなり手軽に扱えるようになったのではないかと思います。 また、java.io パッケージにあるクラスと競合するワケではなく、必要になればそれらのパッケージ内のクラスとも連携がとれるようなので、新しいクラス群を使うハードルも比較的低くなったと思います。Java SE 7 では java.nio.file とそのサブパッケージが追加されました:
java.nio.file パッケージはファイル・システムやファイル操作に関連するクラス群が定義されています。 ただし、簡単なファイル操作で使用するのは
- Path インターフェース
- Paths クラス
- Files クラス
だけなので恐るるにたらずです。 java.nio.file.attribute パッケージにはファイルの属性(アトリビュート)に関するクラス群が定義されています・・・って説明になってませんが。 まぁ、そのうちに。 java.nio.file.spi パッケージは自分でファイルシステムを作らない限り使わないもののようです。
今回は Path インターフェースとPaths クラスを見ていきます。
Path インターフェースと Paths クラスの宣言
java.nio.file パッケージで主要なはたらきをするのは、Path インターフェースとそのインスタンスを生成する Paths クラスです*2。 まずはそれぞれの型宣言を見ていきましょう。Path インターフェース
Path インターフェースは、その名の通りファイルやディレクトリのパスを表す型です。 役割としては java.io.File と同じですが、もっと適切な名前が付けられました。 Path オブジェクトは、java.io.File と同じく、そのオブジェクトが表現するファイルやディレクトリが存在しなくてもインスタンスとして存在することができます。 型宣言はこんなの:package java.nio.file; public interface Path extends Comparable<Path>, Iterable<Path>, Watchable{ // Object, Comparable, Iterable のメソッドは省略 //*****パスの情報を取得する ***** public int getNameCount() public Path getName(int index) public Path getFileName() public Path subpath(int beginIndex, int endIndex) public boolean isAbsolute() public boolean startsWith(Path other) public boolean startsWith(String other) public boolean endsWith(Path other) public boolean endsWith(String other) //***** 別のファイル、ディレクトリへのパスを生成する ***** public Path getParent() public Path getRoot() public Path resolveSibling(Path other) public Path resolveSibling(String other) public Path resolve(Path other) public Path resolve(String other) //***** 等価なパスの別表現を生成する ***** public Path normalize() public Path toAbsolutePath() public Path toRealPath(LinkOption... options) throws IOException public Path relativize(Path other) //***** 他のオブジェクトへ変換する ***** public File toFile() public URI toUri() public String toString() //***** その他のメソッド ***** public FileSystem getFileSystem() public WatchKey register(WatchService watcher, WatchEvent.Kind<?>... events) throws IOException public WatchKey register(WatchService watcher, WatchEvent.Kind<?>[] events, WatchEvent.Modifier... modifiers) throws IOException }
Comparable は java.io.File も拡張してましたが、Path は Iterable<Path> なども継承してます。 ただし、このイテレータはパスの要素を列挙するもので、ディレクトリ内のファイルを列挙するようなものではありません。 Watchable に関しては気が向けばそのうちに。
定義されているメソッドに関しては、ファイル操作(ファイルの生成や削除など)に関連するメソッドが java.nio.file.Files クラスに移され、定義されているメソッドはパス操作に関連するもののみとなっています。 独断と偏見でメソッドを分類するとこんな感じ:
それぞれ、後で見ていきます。
いろいろなアプリケーションでファイルの内容を読み込むパーサ・クラスが使われていると思いますが、それらのクラスに Path オブジェクトから読み込むメソッド(read(Path) や parse(Path) のようなもの)が定義されていけば java.nio.file パッケージも少しは広まっていくんじゃないでしょうかね。
Paths クラス
Paths クラスは、Path オブジェクトを生成するためのユーティリティ・クラスです(ファクトリ・クラスといっていいのかな?)。 定義されているのは Path オブジェクトを生成する static メソッド get() だけです:package java.nio.file; public final Class Paths{ public static Path get(String first, String... more); public static Path get(URI uri); }
使い方は「Path オブジェクトを生成する」の箇所参照。
Path オブジェクトを生成する
Path オブジェクトを取得するためには Paths クラスに定義されている static メソッド get() を用います。 このメソッドは以下の2つがオーバーロードされています:メソッド | 返り値 | 説明 |
---|---|---|
get(String...) get(java.net.URI) |
Path | Path オブジェクトを生成する。 |
使い方を示すサンプルコードを見てみましょう(コードは Groovy で書いてます):
import java.nio.file.* // Path オブジェクトの生成は Paths#get() メソッドで def path = Paths.get("C:/sample/code/of/java/nio/file/PathUsage.java") // バックスラッシュでも区切れる assert path == Paths.get("C:\\sample\\code\\of\\java\\nio\\file\\PathUsage.java") // Groovy での「==」は等値評価(equals() による評価) // 複数の文字列から生成 assert path == Paths.get("C:", "sample", "code", "of", "java", "nio", "file", "FileUsage.java") // java.net.URI から生成 def uri = URI.create("file:///C:/sample/code/of/java/nio/file/PathUsage.java") assert path == Paths.get(uri) // compareTo() メソッド def path1 = Paths.get("C:/sample/code/of/java/nio/file/FileUsage.java") assert path > path1 // assert path.compareTo(path1) > 0
このサンプルは Windows 上で動かすことを念頭において書いてますが、Windows 上でもパス要素の区切りはスラッシュ (/) で動きます*3。 もちろんバックスラッシュ (\) でも OK ですがエスケープが面倒なのでここではあまり使いません*4。
パスの情報を取得する
次はその Path オブジェクトからパス情報を取得するメソッドを見ていきます。 これらの取得できる情報は、パス要素を分離して List になっていると思えば分かりやすいでしょう。 例えばC:/abc/def/ghi
というパスがあれば、
["abc", "def", "ghi"]
という List だと思えば各メソッドの振る舞いが分かりやすいと思います。 ただし、ここでは要素が String のように書きましたが、実際はそれぞれすべてが Path オブジェクトです。 また、絶対パスに関しては startsWith() はルートから始める必要があります。
メソッド | 返り値 | 説明 |
---|---|---|
getNameCount() | int | パス要素の個数を返す。 |
getName(int) | Path | 引数で指定された位置のパス要素を返す。 |
getFileName() | Path | 最後のパス要素を返す*5。 |
subpath(int, int) | Path | 引数で指定された部分パスを返す。 |
isAbsolute() | boolean | 絶対パスかどうかを返す |
startsWith(String) startsWith(Path) |
Path | 引数で指定されたパスから始まるかどうかを返す。 |
endsWith(String) startsWith(Path) |
Path | 引数で指定されたパスで終わるかどうかを返す。 |
では Groovy のサンプルコード:
def path = Paths.get("C:/sample/code/of/java/nio/file/PathUsage.java") println path.getNameCount() // 「7」と表示 // 部分パスを返すメソッド。 返り値は Path オブジェクト println path.getName(0) // 「sample」と表示 println path.getFileName() // 「PathUsage.java」と表示 println path.subpath(0, 3) // 「sample\code\of」と表示 // boolean 値を返すメソッド assert path.isAbsolute() assert path.startsWith("C:/") // String で startsWith() assert !path.startsWith("sample") // 絶対パスの場合はルートから始まる assert path.endsWith(Paths.get("PathUsage.java")) // Path で endsWith() assert !path.endsWith("Usage.java") // 文字列で比較してるわけではない
等価なパスの別表現を生成する
ここでは既に存在している Path オブジェクトを、それと等価な(同じパスを表す)別の Path オブジェクトへ変換するメソッドを見ていきます。 具体的に言うとです。
メソッド | 返り値 | 説明 |
---|---|---|
normalize() | Path | パスを正規化する(., .. などを使わない表現にする)。 |
toAbsolutePath() | Path | 絶対パスに変換する。 |
toRealPath() | Path | パスが表すファイル・ディレクトリが存在すれば絶対パスに変換し、 なければ java.nio.file.NoSuchFileException を投げる。 |
relativize(Path) | Path | このオブジェクトが表すパスに対する引数のパスの相対パスを返す。 |
では Groovy によるサンプルコード:
def path = Paths.get("C:/sample/code/of/java/nio/file/PathUsage.java") // 余剰なパス表現(., .. など)を正規化 def redundantPath = Paths.get("C://sample/code/of/./java/nio/file/../file/PathUsage.java") println redundantPath.normalize() // 「C:\sample\code\of\java\nio\file\PathUsage.java」と表示 // 絶対パスに変換 println path.toAbsolutePath() // 「C:\sample\code\of\java\nio\file\PathUsage.java」と表示 println path.toRealPath() // ファイルが実際に存在すれば「C:\sample\code\of\java\nio\file\PathUsage.java」と表示 // 存在しなければ java.nio.file.NoSuchFileException が投げられる // 相対パスに変換 def nio = Paths.get("C:/sample/code/of/java/nio") println nio.relativize(path) // 「file\PathUsage.java」と表示 // 引数のパスと等価なパスが返される
toRealPath() メソッドは唯一実際に対応するパスがないと例外を投げるメソッドです。
別のファイル、ディレクトリへのパスを生成する
ここでは Path オブジェクトに関係する別の Path を生成するメソッドを見ていきます。メソッド | 返り値 | 説明 |
---|---|---|
getParent() | Path | 親ディレクトリを返す。 |
getRoot() | Path | ルート・ディレクトリを返す。 |
resolveSibling(String) resolveSibling(Path) |
Path | 兄弟要素(同ディレクトリ内のファイル、ディレクトリ)を返す。 |
resolve(String) resolve(Path) |
Path | このオブジェクトが表すパスを起点にして、 引数のパスが相対的に表すパスを返す*6。 |
では Groovy のための(?)サンプルコード:
def path = Paths.get("C:/sample/code/of/java/nio/file/PathUsage.java") // 親ディレクトリ println path.getParent() // 「C:\sample\code\of\java\nio\file」と表示 // ルート・ディレクトリ println path.getRoot() // 「C:\」と表示 // 兄弟要素(同ディレクトリ内のファイル、ディレクトリ) println path.resolveSibling("FilesUsage.java") // 「C:\sample\code\of\java\nio\file\FilesUsage.java」と表示
resolve() メソッドは別途サンプルを書きます:
Path dir1 = Paths.get("C:/sample/code/of/java/nio/file") println dir1.resolve("FilesUsage.java") // 「C:\sample\code\of\java\nio\file\FilesUsage.java」と表示 // 末尾のスラッシュ (/) は無影響 def dir2 = Paths.get("C:/sample/code/of/java/nio/file/") println dir2.resolve("FilesUsage.java") // 「C:\sample\code\of\java\nio\file\FilesUsage.java」と表示 // 以下のようにしても例外は出ない(PathUsage.java がファイルかディレクトリか分からないからだろうけど) def file = Paths.get("C:/sample/code/of/java/nio/file/PathUsage.java") println file.resolve("FilesUsage.java") // 「C:\sample\code\of\java\nio\file\PathUsage.java\FilesUsage.java」と表示
他のオブジェクトへ変換する
最後は他のオブジェクトへ変換するメソッド。 Path オブジェクトには今までの Java I/O で使われていた java.io.File や java.net.URI に変換するメソッドが定義されています:変換メソッド | 変換される型 |
---|---|
toFile() | java.io.File |
toUri() | java.net.URI |
toString() | String |
これらのメソッドによって、いざとなれば今までの Java I/O のプログラミングで使われていたクラスを取得できるので、Path クラスを使う閾も低くなると思います。 ちなみに、java.io.File クラスには対応する Path クラスへ変換する toPath() メソッドも追加されています。
メソッドの使い方は特に問題ないかと:
def path = Paths.get("C:/sample/code/of/java/nio/file/PathUsage.java") assert path.toFile() == new File(/C:\sample\code\of\java\nio\file\PathUsage.java/) assert path.toUri() == URI.create("file:///C:/sample/code/of/java/nio/file/PathUsage.java") assert path.toString() == "C:\sample\code\of\java\nio\file\PathUsage.java" // Windows
ちなみに、Windows で java.io.File クラスのコストラクタにスラッシュ (/) で区切られたパスを渡してもキチンと動作します。
その他のメソッド
その他、今回扱わなかったメソッドにはメソッド | 返り値 |
---|---|
getFileSystem() | FileSystem |
register(WatchService watcher, WatchEvent.Kind<?>... events) register(WatchService watcher, WatchEvent.Kind<?>[] events, WatchEvent.Modifier... modifiers) |
WatchKey |
があります。 これらについては後日やるかも。 やらないかも。

- 作者: 竹添直樹,島本多可子,小津美夕紀,亀井隆司
- 出版社/メーカー: 翔泳社
- 発売日: 2011/07/16
- メディア: 大型本
- 購入: 6人 クリック: 217回
- この商品を含むブログ (25件) を見る