File("xxxx")なんてコードをよく見かけます。!!!!!!!!!!ということで、Javaによる最新(いつの話ですか!)ファイルI/Oのご紹介です。Fileに代わるPathjava.nio.fileパッケージには、ファイルやディレクトリを操作する便利なクラスやインターフェイスが用意されています。その中でも、ベースとなるのが多分Pathインターフェイスでしょう。Pathを作る下記のようにして作成します。下記のような記述でも作成できます。上記の、path1とpath2は同じファイルを表現するので、equalsメソッドで比較するとtrueが返ります。下記のような記述では注意が必要です。Windowsの環境では、問題なくファイルパスと認識されるのですが、私の環境(Linuxのデスクトップ)では単一のファイル(名前)と認識されてしまいます。逆に、Windows環境で"/home/foo/currentDir/java.txt"を引数に作成した場合は、正しいファイルパスとして認識されます。Pathを操作するこのクラスには、ファイルパスを操作する便利な機能が様々実装されています。基本的にはJavaDocを参照していただくとして、よく使うと思われるいくつかを紹介します。相対パスを絶対パスに変換する上記コードは、私の環境では下記のように出力します(カレントディレクトリが/home/foo/currentDirだとすると)。java.txt/home/foo/currentDir/java.txtWindows環境では下記のように出力します(カレントディレクトリがC:\home\foo\currentDirだとすると)。java.txtC:\home\foo\currentDir\java.txt親ディレクトリを取得する上記コードは、下記のように出力します(カレントディレクトリが/home/foo/currentDirだとすると)。/home/foo/currentDirパスを解決する上記コードは、下記のように出力します(カレントディレクトリが/home/foo/currentDirだとすると)。/home/foo/currentDir/c.txt親のパスに対してパスを解決する上記コードは、下記のように出力します(カレントディレクトリが/home/foo/currentDirだとすると)。/home/foo/currentDir/c.txt(3)と同じことを、わざわざ親ディレクトリを取得しないで実現できます。ファイル名だけ取得する上記コードは、下記のように出力します。java.txtjava.txtどうしてもFileが使いたいありますよ。実際のファイルやディレクトリを操作する論理パスではなく、実際のファイルやディレクトリを操作するためには、java.nio.file.Filesクラスを使います。このクラスには、ファイルやディレクトリを操作/参照する便利な機能が様々実装されています。こちらも基本的にはJavaDocを参照していただくとして、よく使うと思われるいくつかを紹介します。ファイルの情報を取得するPathに該当するファイルが本当に存在するか確認するpathに該当するファイルやディレクトリが存在すれば、trueが返ります。8601形式となります。2020-01-30T08:10:51.365231Zローカル日付に変換して、フォーマットを変更する少々本題からは外れますが、UTCでは使い難いのでFileTimeをローカル日付に変換する方法です。(2)のソースの続きです。17:10:51DateTimeFormatter#ofPatternが返すインスタンスはスレッドセーフなので、SimpleDateFormatの様に使う度に作成する必要はありません。日付は和暦以外認めませんだいぶ本題から外れますが、和暦で表示する方法です。LocalDateTimeを取得する箇所までは、(3)と同じです。和暦で表示する場合は、java.time.chrono.JapaneseDateを使います。3行目で、LocalDateTimeからJapaneseDateに変換しています。JapaneseDateは日付しか保持しないので、時分秒までフォーマットしようとすると、例外がスローされます。このため、時刻はLocalDateTimeから取得します。令和に対応していないバージョンのJDKを使った場合は、当然「令和」とは表示されません。ファイルを読み込むバイナリとして一気に読み込むファイルの読み込みは、このクラスのおかげでとても簡単になりました。読み込んだサイズ:57バイトテキストとして一気に読み込むこちらも、ワンステップでリストに格納してくれるので、とても簡単です。このファイルは、日本語ですSJISでエンコードされていますもちろん文字コードも指定できます。文字コードを指定しない場合(Files#readAllLinesの第ニ引数がないバージョン)は、ファイルの内容がUTF-8としてデコードされます。環境依存ではなくなったということですね。マルチバイト文字のエンコード/デコードまたまた本題からはそれますが、Charsetのおかげで、地味にマルチバイト文字のエンコード/デコードが楽になりました。String#getBytes(String)は例外をスローするのでtry〜catchで囲わざるを得ず、テストでカバレッジを100%にしたいがために、不自然なコーディングを余儀なくされたものでした。Charset#forNameはランタイム例外しかスローしないので、無駄なtry〜catchも必要なくなりました。String#getBytes(Charset)はJDK1.6からのサポートなので、今更何をって感じですかね。テキストとして一行ずつ読み込むおっと、一気にJava8っぽくなってきました。関数型インターフェイスにアロー演算子、ラムダ式の登場です。関数型プログラミングってやつですね。CPUのマルチコア化が進んで注目されているパラダイムです。オブジェクト指向と比べて...。おっと、このあたりは沼なので、さらっとこの程度で(^_^;上記コードは関数型インターフェイスを強調するためにConsumerを登場させていますが、下記のようにも記述できます(こちらのほうが一般的でしょうか)。Files#linesが返すStreamは、Files#readAllLinesと違い(関数型プログラミングなので)遅延評価されます。上限が不明な巨大ファイルを操作するような場合、Files#readAllLinesは危険で使えませんが、Files#linesを使えば一定サイズのバッファリングで処理される(筈)ので、巨大なメモリを用意しなくても大丈夫です。注意が必要なのは、エラーが発生するタイミングです。JavaDocにも記述されていますが、Files#linesがスローするIOExceptionは、ファイルオープン時のエラーです。リード中のエラーは、Streamの評価中にUncheckedIOExceptionとしてスローされます。上記コード上では、4行目に当たります。そのため、7行目でキャッチしている例外をExceptionとしています。全ての処理が終了した時点でStreamのクローズも必要です(特にサーバの処理では、ガベージコレクションに任せると痛い目にあいます)。ファイルに書き込むバイナリとして一気に書き込むファイルの書き込みも、このクラスのおかげでとても簡単になりました。現在のサイズ:7バイトテキストとして一気に書き込むこちらも、ワンステップでリストから書き込んでくれるので、とても簡単です。現在のサイズ:56バイト書き込む時に、環境標準の改行コードが各行の終端に付加されます。Files#writeは、第4引数以降(Charsetを指定する場合。Charsetを指定しない場合は第3引数以降)に、ファイルをオープンする際のオプションを指定できます。オプションを指定しない場合、指定のファイルが存在しなければ作成し、存在した場合はオープン時に、サイズ0となります。テキストとして随時書き込む先程はListを渡しましたが、Files#writeの第2引数はjava.lang.Iterableなので、事象が発生した時点で随時書き込むということも可能です。hasNextの中で、事象の発生か終了を待って値を返すようにすれば、随時書き込みの完成です。ディレクトリを渡り歩く以下のようなディレクトリ構成を前提として説明します。+html_file_01.htmlディレクトリのファイルを取得する${user.home}/tmp/test/text_file_01.txt${user.home}/tmp/test/text_file_02.txt${user.home}/tmp/test/html_file_01.html${user.home}/tmp/test/sub_dir_01${user.home}/tmp/test/sub_dir_02指定のパス(この場合は${user.home}/tmp)の直下にあるファイルとディレクトリを一覧します。全てのファイルとディレクトリを取得する${user.home}/tmp/test${user.home}/tmp/test/text_file_01.txt${user.home}/tmp/test/text_file_02.txt${user.home}/tmp/test/html_file_01.html${user.home}/tmp/test/sub_dir_01${user.home}/tmp/test/sub_dir_01/sub_dir_text.txt${user.home}/tmp/test/sub_dir_02${user.home}/tmp/test/sub_dir_02/sub_dir_text.txt${user.home}/tmp/test/sub_dir_02/sub_dir_html.html${user.home}/tmp/test/sub_dir_02/sub_dir_html.htm指定のパスを含んだ配下にある全てのファイルとディレクトリを一覧します。特定の拡張子のファイルを取得する${user.home}/tmp/test/text_file_01.txt${user.home}/tmp/test/text_file_02.txt複数の拡張子を指定する場合は、下記のように指定します。${user.home}/tmp/test/sub_dir_02/sub_dir_html.html${user.home}/tmp/test/sub_dir_02/sub_dir_html.htm。