読者です 読者をやめる 読者になる 読者になる

倭マン's BLOG

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

これからの「Java I/O」の話をしようwww (12) : ファイルシステム関連の型 FileSystem, FileSystems, FileStore

java.io/nio

今回は今まで見てきた Path, Files クラスのメソッドで積み残している

  • Path#getFileSystem()
  • Files#getFileStore(Path)

を踏まえて、ファイルシステムやファイルストア(Windows のドライブ)に関連する型を見ていきます(目次)。 上記の2つのメソッドはそれぞれ Path オブジェクトによって指定されるファイルが属するファイルシステム、ファイルストアを返すだけのメソッドです(メソッドの説明終わり)。

Windows では、ファイルシステムはいくつかのファイルストアを含み、ファイルストアはルートディレクトリ (root directory) を頂点とする樹木構造によって複数のファイル、ディレクトリを含むというようなイメージです*1。 Unix 系 OS でもドライブの代わりに /media ディレクトリ下のデバイスディレクトリが同じように扱われるんだと思いますが、どうなんでしょう? 誰か試して~。

さて、この記事で見ていくのは具体的には次の3つの型です:

  • java.nio.file.FileSystem
  • java.nio.file.FileSystems
  • java.nio.file.FileStore

FileSystems クラスは FileSystem に対してのユーティリティクラスで、static なファクトリ・メソッドがあれこれ定義されています。

FileSystem, FileSystems クラス

まずは FileSystem クラスとそのユーティリティクラスである FileSystems クラスを見ていきましょう。

FileSystem クラス

package java.nio.file;

public abstract class FileSystem implements Closeable, AutoCloseable{

    //***** Constructor *****
    protected FileSystem()

    //***** File System Info *****
    public FileSystemProvider provider()
    public boolean isReadOnly()
    public String getSeparator()
    public Set<String> supportedFileAttributeViews()

    //***** Open/Close *****
    public boolean isOpen()
    public void close() throws IOException

    //***** File System Accessors *****
    public Iterable<FileStore> getFileStores()
    public Iterable<Path> getRootDirectories()
    public Path getPath(String first, String... more)

    //***** Services *****
    public PathMatcher getPathMatcher(String syntaxAndPattern)
    public UserPrincipalLookupService getUserPrincipalLookupService()
    public WatchService newWatchService() throws IOException
}
  • メソッドの分類は、まぁ適当です。 拙者の独断と偏見。
  • getSeparator() メソッドが返す文字列はパス区切り文字です。 Unix 系ではスラッシュ (/)、Windows ではバックスラッシュもしくは円記号 (\) です。 デフォルトのファイルシステムでは java.io.File.separator と同じ文字です。
  • supportFileAttributeViews() メソッドはこのファイルシステムがサポートしている FileAttributeView の短縮名を返します。 例えば PosixFileAttributeView では「posix」、DosFileAttributeView では「dos」などです。
  • FileSystem クラスが Closable, AutoClosable を実装している通り、ファイルシステムには開閉があります。 ただし、デフォルトのファイルシステムは close() メソッドを呼んでも閉じることはできません(UnsupportedOperationException が投げられます)。
  • getFileStore() メソッドはこのファイルシステムに含まれるファイルストア(Windows のドライブ)を返します。 また getRootDirectories() メソッドはそれらのファイルストアのルートディレクトリを返します。
  • getPathMatcher() メソッドの返り値の PathMatcher クラスは以前の記事『これからの「Java I/O」の話をしようwww (9) : Files クラスのメソッド 〜ディレクトリの階層を走査〜』で少し出てきました。 Files#newDirectoryStream(Path, String) メソッドにも(内部で)関係あるようです。
  • getUserPrincipalLookupService() メソッドは以前の記事『これからの「Java I/O」の話をしようwww (6) : Files クラスのメソッド 〜ファイル、ディレクトリの属性〜』でファイル所有者を取得するのに使ってました。
  • newWatchService() メソッドの返り値の WatchService クラスはそのうちやる予定。

FileSystems クラス
FileSystems クラスは FileSystem に関するユーティリティクラスです:

package java.nio.file;

public final class FileSystems {

    public static FileSystem getDefault()

    public static FileSystem newFileSystem(Path path, ClassLoader loader)
        throws IOException

    //***** URI から取得/生成 *****
    public static FileSystem getFileSystem(URI uri)

    public static FileSystem newFileSystem(URI uri, Map<String,?> env)
        throws IOException

    public static FileSystem newFileSystem(URI uri, Map<String,?> env, ClassLoader loader)
        throws IOException
}
  • 定義されているメソッドは今のところ FileSystem の static ファクトリメソッドのみのようです(getXxxx() メソッドをファクトリメソッドと呼んでいいのかどうかは知りませんが)。
  • getDefault() メソッドはデフォルトの、当該 JVM が稼働しているファイルシステムを返します。 FileSystems クラスのメソッドで使うのはだいたいこのメソッドだと思います。
  • getDefault() メソッド以外のメソッドは試してません。 ネットワーク越しとかデュアル(以上)ブートの PC とかで使うのかな? (JavaDoc すら読んでねー)

サンプルコード
さて、以上を踏まえてサンプルコードを見ていきましょう(例によって Groovy で書いてます。 ある程度 Java に似せているので Groovy 知らなくてもメソッドの使い方はわかるかと*2)。 まぁ、自分の PC 環境であれこれ試してみた方が面白いかと。

import java.nio.file.FileSystems
import java.nio.file.Paths

def fileSystem = FileSystems.getDefault()
println(fileSystem)  // 「sun.nio.fs.WindowsFileSystem@000000」などと表示

// Windows で実行
//***** Properties *****
println("provider  :  " + fileSystem.provider())
    // 「provider : sun.nio.fs.WindowsFileSystemProvider@aa0000」などと表示
println("isOpen    : " + fileSystem.isOpen())  // 「isOpen : true」と表示
println("isReadOnly: " + fileSystem.isReadOnly())  // 「isReadOnly: false」と表示
println("Separator : " + fileSystem.getSeparator())  // 「Separator: \」と表示

try{
    fileSystem.close()
}catch(UnsupportedOperationException ex){
    println "デフォルトのファイルシステムは閉じることができません。"
}

//***** FileStore/File *****
println(fileSystem.supportedFileAttributeViews().join(", "))
    // 「owner, dos, acl, basic, user」と表示
println(fileSystem.getFileStores().join(", "))
    // 「TI00000000B (C:), HD-XXX2 (E:), FLASH DRIVE (F:)」などと表示
println(fileSystem.getRootDirectories().join(", "))
    // 「C:\, D:\, E:\, F:\」などと表示
println(fileSystem.getPath(".").toAbsolutePath())
    // 「C:\Users\waman\workspace\groovy\nio-test\src\.」などと表示

//***** Path#getFileSystem() メソッド *****
def fs = Paths.get(".").getFileSystem()
assert fs == fileSystem
  • コメントにある表示はもちろん動作環境(OS など)によって異なります。 上記のサンプルでは Windows で動かした結果です。
  • supportedFileAttributeViews() メソッドで返される文字列 owner, dos, acl, basic, user(, posix) はそれぞれ FileAttributeView クラスのサブクラス名を簡略化した名前です。 各文字列がどの FileAttributeView クラスに対応するかは java.nio.file.attribute パッケージに定義されているクラスを参照。
  • 拙者の環境では D ドライブは DVD ドライブなんですが、このドライブはルートディレクトリとしては返されますが、DVD を挿入していないとファイルストアとしては認識されないようです。

FileStore クラス

次は FileStore クラス。 Windows ではドライブにあたるものです。 クラス定義はこんなの(例によって、分類は拙者の独断と偏見):

package java.nio.file;

public abstract class FileStore {

    //***** Constructor *****
    protected FileStore()

    //***** Properties *****
    public String name()
    public String type()
    public boolean isReadOnly()

    //***** Space *****
    public long getTotalSpace() throws IOException
    public long getUnallocatedSpace() throws IOException
    public long getUsableSpace() throws IOException

    //***** File Attribute *****
    public boolean supportsFileAttributeView(Class<? extends FileAttributeView> type)
    public boolean supportsFileAttributeView(String name)

    //***** File Store Attributes *****
    public Object getAttribute(String attribute) throws IOException

    public <V extends FileStoreAttributeView>
    V getFileStoreAttributeView(Class<V> type)
}
  • 3つの getXxxx() メソッドは名前が示すメモリ容量を返します。 拙者の環境では getUnallocatedSpace() と getUsableSpace() は同じ値を返してます。
  • supportsFileAttributeView() メソッドは、このファイルストアに含まれるファイルが指定されたファイル属性を持つかどうかを返します。 文字列を指定する場合は、FileSystem#supportedFileAttributeViews() で返されるような簡略名の文字列を指定します。
  • getAttribute() メソッドはファイルストアのファイルストア属性を返します。 「posix」や「dos」などのファイル属性とは異なります。 getFileStoreAttributeView() メソッドは、ファイルに対する FileAttributeView クラスのように、ファイルストア属性の変更を型安全に行うメソッドだと思いますが、現在のところ FileStoreAttributeView の具象サブクラスが標準 API に定義されていないので使いようがないですね。
  • 大抵の場合、各 FileStore は1つのルートディレクトリを持つと思いますが(Unix 系の OS では違うのかな?)、FileStore オブジェクトからルートディレクトリを取得するメソッドは定義されていないようです*3

ではサンプルコード。

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

def fileStore = Files.getFileStore(Paths.get("."))
println(fileStore)  // 「TI00000000B (C:)」などと表示

//***** Basic Attribute *****
println("name: " + fileStore.name())  // 「name: TI00000000B」
println("type: " + fileStore.type())  // 「type: NTFS」
println("Read Only: " + fileStore.isReadOnly())  // 「Read Only: false」

//***** Space *****
println("Total Space      : " + fileStore.getTotalSpace())
println("Unallocated Space: " + fileStore.getUnallocatedSpace())
println("Usable Space     : " + fileStore.getUsableSpace())

//***** File Attribute *****
// クラスオブジェクトで確認
println(fileStore.supportsFileAttributeView(DosFileAttributeView.class))  // 「true」
// 文字列で確認
println(fileStore.supportsFileAttributeView("dos"))  // 「true」

//***** File Store Attribute *****
println(fileStore.getFileStoreAttributeView(FileStoreAttributeView.class))  // null
// println(fileStore.getAttribute("zfs:compression"))

//***** Files#getFileStore() メソッド *****
def fs = Files.getFileStore(Paths.get("."))
assert fs == fileStore
  • FileStore オブジェクトに対して toString() を読んだ場合には、name() メソッドの返り値の名前に加えてルートディレクトリのパス(ここでは「C:」)が追加されています。 ただし、これを単独で取得する方法が見当たらないのが謎。 toString() で表示される情報には API でアクセスできるべし、みたいなことが『Effective Java』に書いてたような気がするが。 このルートディレクトリパスは常に存在するわけではないのかな?

まぁ、これも自分の環境であれこれ動かしてみた方が楽しそうですね。 特に Windows 以外の方、試してみてちょ。

さて、次は WatchService をやろうと思ってたんですが、ファイルシステムやファイル属性をイジってたついでに ACL (Access Control List アクセス制御リスト)関連の API をやります。 POSIX ファイルシステム(Unix 系)だけでなく Windows でもサポートされてるので POSIX 理解するより汎用的なのではなかろうかという思惑。

お気に入りのUbuntu 14.04 LTS日本語Rem―無償OS &無償ソフトで何でも揃う!

お気に入りのUbuntu 14.04 LTS日本語Rem―無償OS &無償ソフトで何でも揃う!

Windows→Ubuntu乗り換え 100%活用ガイド (100%ガイド)

Windows→Ubuntu乗り換え 100%活用ガイド (100%ガイド)

*1:ただし、後のサンプルで見るように、DVD ドライブはルートディレクトリを返しても、DVD を挿入していないとファイルストアとしては認識されていない、みたいなこともあるようです。

*2:Java と変えてるのは、変数の型を def に、行末のコロンを省略、System.out.println を println に、くらいです。 真に Groovy を使えばもっと簡略して書ける部分は多々ありますが。

*3:ファイルストアからそのルートディレクトリを取得するの、ちょっと面倒というか OS によって場合分けする必要があるもよう。 「Find the directory for a FileStore」参照。