Files
クラスもまた、java.nio.file
パッケージの主要なエントリ・ポイントです。 このクラスには、ファイルやディレクトリの読取り、書込み、操作に関する豊富な静的メソッドが用意されています。 Files
のメソッドは、Path
オブジェクトのインスタンスを処理します。 今後のセクションに進む前に、次の共通概念について理解してください。
ストリームやチャネルなど、このAPIで使用されるリソースの多くは、java.io.Closeable
インタフェースを実装するか継承しています。 Closeable
なリソースは、リソースが不要になった場合、close
メソッドを呼び出してリソースを解放する必要があります。 リソースをクローズしないと、アプリケーションのパフォーマンスが低下する可能性があります。 次のセクションで説明するtry-
with-resources文を使用すると、この手順が自動的に処理されます。
ファイルI/Oでは、予期しない状況を完全に防ぐことはできません。 想定と異なるファイルが存在する(またはファイル自体が存在しない)、プログラムにファイル・システムへのアクセス権がない、デフォルトのファイル・システム実装が特定の機能をサポートしていないといった状況が考えられます。 非常に多くのエラーが発生する可能性があるのです。
ファイル・システムにアクセスするすべてのメソッドで、IOException
がスローされる可能性があります。 ベスト・プラクティスは、Java SE 7リリースで導入されたtry-
with-resources文の中にこれらのメソッドを記述し、IOException
をキャッチすることです。 try-
with-resources文のメリットは、不要になったリソースをクローズするコードがコンパイラによって自動生成されることです。 次のコードは、この文の使用法を示しています。
Charset charset = Charset.forName("US-ASCII"); String s = ...; try (BufferedWriter writer = Files.newBufferedWriter(file, charset)) { writer.write(s, 0, s.length()); } catch (IOException x) { System.err.format("IOException: %s%n", x); }
別の方法として、try
ブロック内にファイルI/Oメソッドを記述し、例外をcatch
ブロックでキャッチすることもできます。 ただしこの場合は、オープンしたストリームやチャネルがあれば、そのすべてをfinally
ブロックでクローズする必要があります。 try-catch-finallyアプローチを使用した場合、上のコードは次のように変わります。
Charset charset = Charset.forName("US-ASCII"); String s = ...; BufferedWriter writer = null; try { writer = Files.newBufferedWriter(file, charset); writer.write(s, 0, s.length()); } catch (IOException x) { System.err.format("IOException: %s%n", x); } finally { if (writer != null) writer.close(); }
IOException
に加えて、個別の例外の多くがFileSystemException
を継承しています。 このクラスには、関連ファイルを返すメソッド(getFile
)、詳細メッセージ文字列を返すメソッド(getMessage
)、ファイル・システム操作が失敗した理由を返すメソッド(getReason
)、関係する"その他の"ファイル(存在する場合)を返すメソッド(getOtherFile
)などの便利なメソッドが含まれています。
次のコードは、getFile
メソッドの使用方法を示したものです。
try (...) { ... } catch (NoSuchFileException x) { System.err.format("%s does not exist\n", x.getFile()); }
読みやすくするために、このレッスンのファイルI/Oサンプル・コードには例外処理が記述されていませんが、実際にコードを作成するときは必ず例外処理を記述してください。
Files
のメソッドの中には、任意の数の引数を受け入れるものがあります。このようなメソッドは、そのシグネチャで見分けることができます。 たとえば次のメソッド・シグネチャの場合、CopyOption
引数に付いている省略記号が、メソッドを呼び出す際に渡す引数の数が決まっていない(つまり可変引数である)ことを示しています。
Path Files.move(Path, Path, CopyOption...)
メソッドが可変引数を受け入れる場合は、値をカンマで区切ったリストか、または値の配列(CopyOption[]
)を渡すことができます。
たとえば上記のmove
メソッドは、次のように呼び出すことができます。
import static java.nio.file.StandardCopyOption.*; Path source = ...; Path target = ...; Files.move(source, target, REPLACE_EXISTING, ATOMIC_MOVE);
可変引数構文の詳細は、『Arbitrary Number of Arguments』を参照してください。
move
をはじめ、いくつかのFiles
メソッドでは、一部のファイル・システムで特定の操作を原子的に実行できます。
原子的なファイル操作とは、中断や"部分的な"実行が不可能な操作のことです。 つまり、操作全体が実行されない場合には、この操作は失敗となります。 これは、複数のプロセスがファイル・システムの同じ領域で動作し、各プロセスが完全なファイルにアクセスすることを保証する必要がある場合に重要です。
多くのファイルI/Oメソッドは、メソッド・チェーンの概念に対応しています。
最初に、あるオブジェクトを返すメソッドを呼び出します。 その直後に、今返されたオブジェクトのメソッドを呼び出し、それによってまた別のオブジェクトが返される、というように呼出し処理を連続して行います。 I/Oの多くのサンプル・コードでは、このテクニックが次のように使用されています。
String value = Charset.defaultCharset().decode(buf).toString(); UserPrincipal group = file.getFileSystem().getUserPrincipalLookupService().lookupPrincipalByName("me");
このテクニックによってコードが短くなり、不要な一時変数を宣言する必要もなくなります。
Files
クラスでは、2つのメソッドがグロブ引数に対応しています。では、グロブとは何でしょうか。
グロブ構文を使用すると、パターン・マッチングの動作を指定できます。
グロブ・パターンは文字列として指定し、ディレクトリ名やファイル名などの他の文字列と一致します。 グロブ構文には、いくつかの単純なルールがあります。
*
)は、任意の数の文字(0文字を含む)を表します。
**
)は*
と同様に動作しますが、ディレクトリ境界を横断します。 この構文は一般的に、完全なパスと一致させるために使用されます。
?
)は、1つの文字を表します。
{sun,moon,stars}
は、"sun"、"moon"、または"stars"と一致します。
{temp*,tmp*}
は、"temp"または"tmp"で始まるすべての文字列と一致します。
-
)と併用して文字の範囲を表します。 次のように使用します。
[aeiou]
は、小文字の母音のアルファベット(a、e、i、o、u)のいずれかと一致します。
[0-9]
は、任意の数字と一致します。
[A-Z]
は、任意の大文字のアルファベットと一致します。
[a-z,A-Z]
は、任意の大文字または小文字のアルファベットと一致します。
*
、?
、\
は、その文字そのものを表します。
*
、?
などの特殊文字を、その文字そのものとして使用するには、バックスラッシュ文字(\
)を使用してエスケープします。 たとえば、 \\
は単一のバックスラッシュと一致し、\?
は疑問符と一致します。
次に、グロブ構文の例を示します。
*.html
という構文は、.htmlで終わるすべての文字列と一致します。
???
という構文は、3つの文字または数字によるすべての文字列と一致します。
*[0-9]*
という構文は、数字1文字を含むすべての文字列と一致します。
*.{htm,html,pdf}
という構文は、.htm、.html、.pdfのいずれかで終わるすべての文字列と一致します。
a?*.java
という構文は、a
で始まり、1つ以上の文字または数字が続き、.javaで終わるすべての文字列と一致します。
{foo*,*[0-9]*}
という構文は、fooで始まるすべての文字列、または数字1文字を含むすべての文字列と一致します。
"*"
)か、バックスラッシュを使用する(\*
)か、コマンドラインでサポートされる何らかのエスケープ手法を使用する必要があります。
グロブ構文は機能的で簡単に使用できますが、 ニーズに対応しきれない場合は正規表現を使用することもできます。 詳細は、『Regular Expressions』レッスンを参照してください。
グロブ構文に関する詳細は、FileSystem
クラスのgetPathMatcher
メソッドのAPI仕様を参照してください。
Files
クラスは"リンクの認識"が可能なクラスです。 すべてのFiles
メソッドは、シンボリック・リンクがある場合に対処方法が自動的に検出されるか、またはシンボリック・リンクがある場合の動作を設定できるオプションを有しています。