倭マン's BLOG

くだらない日々の日記書いてます。 たまにプログラミング関連の記事書いてます。 書いてます。

これからの「Java I/O」の話をしようwww (3) : Files クラスのメソッド 〜ファイル、ディレクトリの作成〜

Java nio の API を見ていくシリーズ(目次)。 今回から java.nio.file.Files クラスに定義されているメソッドを見ていきますヨ〜。 今回はファイルやディレクトリを作成するメソッドです。 これをもう少し分類すると、以下のようなメソッドがあります:

加えて、FileAttribute についても見ていきます:

それぞれ見ていきましょう。

【修正】

  • 「テンポラリ・ファイル」、「テンポラリ・ディレクトリ」と書いていた箇所を「一時ファイル」、「一時ディレクトリ」に変更しました。
  • 一時ファイル、ディレクトリを作成するサンプルコードから例外処理を削除しました。

ファイル、ディレクトリを作成する

まずは一番基本のファイル、ディレクトリを作成するメソッド。

メソッド 返り値 説明
createFile(Path, FileAttribute<?>...) Path ファイルを作成する。
createDirectory(Path, FileAttribute<?>...) Path ディレクトリを作成する。
ディレクトリがなければ例外が投げられる。
createDirectories(Path, FileAttribute<?>...) Path ディレクトリ階層を作成する。
ディレクトリがなければそれらも作成する。

返り値の Path オブジェクトは引数の Path オブジェクトです。

2つ目と3つ目のメソッドはどちらもディレクトリを作成しますが、指定したディレクトリのディレクトリがない場合に挙動が異なります*1。 親ディレクトリがない場合に createDirectory() メソッドは例外 NoSuchFileException が投げられるのに対して、createDirectories() メソッドは親ディレクトリも作成します。 ちなみに、createFile() メソッドは親要素がないと例外 NoSuchFileException を投げます。

FileAttribute については後で見ることにして、これらのメソッドを簡単に使ったサンプルコードを見ていきましょう(Groovy により記述。 なるべく Java っぽく書いてますが):

import java.nio.file.*

// ディレクトリ階層を一気に作成する
def dir = Paths.get("C:/sample/code/of/java/nio")
Files.createDirectories(dir)    // ディレクトリ「C:\sample\code\of\java\nio」が作成される

// ディレクトリを作成する(祖先ディレクトリがなければ例外 NoSuchFileException が投げられる)
def parent = Paths.get("C:/sample/code/of/java/nio/file")
Files.createDirectory(parent)
    // ディレクトリ「C:\sample\code\of\java\nio\file」が作成される

// ファイルを作成する
def path = Paths.get("C:/sample/code/of/java/nio/file/FilesUsage.java")
Files.createFile(path)
    // ファイル「C:\sample\code\of\java\nio\file\FilesUsage.java」が作成される

まぁ、特に問題はないかと。

一時ファイル、一時ディレクトリを作成する

次は一時ファイル(テンポラリ・ファイル)、一時ディレクトリ(テンポラリ・ディレクトリ)を作成するメソッド。 一時的に使用するファイルやディレクトリですね。 関連するメソッドには下表のようなものがあります:

メソッド 返り値 説明
createTempFile(Path, String, String, FileAttribute<?>...)
createTempFile(String, String, FileAttribute<?>...)
Path 一時ファイルを作成する。
createTempDirectory(Path, String, FileAttribute<?>...)
createTempDirectory(String, FileAttribute<?>...)
Path 一時ディレクトリを作成する。

引数の Path オブジェクトは一時ファイル、ディレクトリを作成するディレクトリへのパスです。 createTempFile() メソッドの場合もそうなので注意。 というか、作成される一時ファイル、ディレクトリの名前は自分では決められません(接頭辞、接尾辞は付けられる)。 作成されたファイル、ディレクトリの名前(というかパス)はメソッド返り値の Path オブジェクトから取得できます。

Path オブジェクトを引数にとらないメソッドは、システム規定の場所にファイルやディレクトリが作られます。 作成された場所はメソッド返り値の Path オブジェクトによって参照できます*2。 デフォルトではシステムプロパティ「java.io.tmpdir」で返されるパス(の文字列表現)で指定されるディレクトリに作成されるようです:

Path tempDir = Paths.get(System.getProperty("java.io.tmpdir"));

では、サンプルコード:

def dir = Paths.get("C:/sample/code/of/java/nio/file")
Files.createDirectories(dir)

// 一時ディレクトリを作成する
def tempdir =  Files.createTempDirectory(dir, "temp")
Files.createTempDirectory(tempdir)
    // ディレクトリ「C:\sample\code\of\java\nio\file\temp##########」が作成される

// 一時ファイルを作成する
def tempFile = null
Files.createTempFile(dir, "temp", ".java")
    // ファイル「C:\sample\code\of\java\nio\file\temp##########.java」が作成される

一時ファイルなので、アプリケーション終了時に削除されます。

次はリンクやシンボリック・リンクの作成。 これらのファイルタイプは java.nio で新しくサポートされました。 リンクとシンボリック・リンクの違いは

リンク 通常のファイルとほとんど見分けがつかない。
リンク・ファイルに対する読み書きが、意識することなくリンク先のファイルへの読み書きになる。
シンボリック・リンク ファイルがシンボリック・リンクのファイルかどうかが判定できる*3
リンク先の解決をプログラマーが自分で行う必要がある*4

などです。 詳しくは The Java Tutorials 「Links, Symbolic or Otherwise」参照。 シンボリック・リンクに関係するメソッドは Files クラスにいくつかありますが、リンクに関するメソッドは作成以外にないことに注意。

リンク、シンボリック・リンクを作成するメソッドは下表の通り:

メソッド 返り値 説明
createLink(Path, Path) Path リンクを作成する
createSymbolicLink(Path, Path) Path シンボリック・リンクを作成する

ではサンプルコード。 サンプルではリンク、シンボリック・リンクともに同じファイル(C:/sample/code/of/LinkTarget.java)をリンク先にしています:

def dir = Paths.get("C:/sample/code/of/java/nio/file")
Files.createDirectories(dir)

// リンク対象のファイルを作成する
def target = Paths.get("C:/sample/code/of/LinkTarget.java")
Files.createFile(target)

// リンクを作成する
Path link = dir.resolve("LinkUsage.lnk");
Files.createLink(link, target);    // リンク「C:\sample\code\of\LinkUsage.java」が作成される

Files.write(link, "link file content".bytes)
println Files.readAllLines(target, java.nio.charset.Charset.defaultCharset())
    // 「link file content」と表示される!

// シンボリック・リンクを作成する
def symbolicLink = dir.resolve("SymbolicLinkUsage.lnk")
Files.createSymbolicLink(symbolicLink, target)
    // リンク「C:\sample\code\of\java\nio\file\SymbolicLinkUsage.java」が作成される

println Files.readSymbolicLink(symbolicLink)
    // 「C:\sample\code\of\java\nio\file\LinkTarget.java」が表示される(ハズ)
  • リンクを作成した後で、リンクに対して「link file content」という文字列を書き込み、リンク先のファイルから内容を読み取ると、正にその内容が取得できます。
  • シンボリック・リンクに関しては、Windows XP ではサポートされてませんでした・・・*5 Windows のショートカットって、似てるけどシンボリック・リンクじゃないようです*6

FileAttribute を設定する

最後は、上記のいくつかのメソッドに引数として渡せる FileAttribute の使い方。 今のところ、POSIX ファイルシステム(Uinx 系のファイルシステムと言えばいいのかね)のファイル・パーミッション('rwxr-x---' みたいなやつ)の指定しかサポートされてないようです(たぶん)。 使い方は以下の通り(たぶん):

import java.nio.file.*
import java.nio.file.attribute.PosixFilePermissions

// POSIX ファイル・パーミッション
def dir = Paths.get("C:/sample/code/of/java/nio/file")
def posixFile = dir.resolve("PosixFileUsage.java")
Files.createFile(posixFile, posixFilePermissions("rwxr-x---"))
    // 指定したパーミッションでファイル
    // 「C:\sample\code\of\java\nio\file\PosixFileUsage.java」が作成される(ハズ)

def FileAttribute<Set<PosixFilePermission>> posixFilePermissions(String s){
    // "rwxr-x---" のような文字列から FileAttribute<?> オブジェクトを生成する
    return PosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString(s))
}

Windows XP ではサポートされていないので、例外が投げられました・・・

現場で使えるJavaライブラリ

現場で使えるJavaライブラリ

*1:他にも、既に同パスのディレクトリがある場合にcreateDirectory() メソッドは例外 FileAlreadyExistsException を投げる一方、createDirectories() メソッドは例外を投げないなどの違いもあります。 ちなみに、同パスのファイルがある場合はどちらも例外を投げます。

*2:Windows XP では「C:/Documents and Settings/《ユーザー名》/Local Settings/Temp」に作成されましたが、少々謎が。 このディレクトリって、一時ファイル、ディレクトリを保存しておく場所だと思うけど、山のようにファイル、ディレクトリが残されてました。 で、結構容量食ってたので削除すると、デスクトップのアイコンが全て削除されるという、意味不明な結果が・・・ この OS、一体どんな実装してるんだい?

*3:Files.isSymbolicLink() によってできます。

*4:Files.readSymoblicLink() メソッドによってできます。

*5:Vista 以降の Windows なら動くそうです。

*6:逆に、「ショートカット」を別途作成して java.nio.file パッケージのクラスで読み込むと、拡張子が「.lnk」の普通のファイルって扱いっぽいです。 でも、拡張子が「.lnk」のリンクを作成しても「不正なショートカット」と認識されてしまうようで・・・どうしろって言うんだい!