Filesクラスのファイル及びディレクトリ操作のメソッドを確認する前に、
まずは、OSのファイルシステムでファイル及びディレクトリに対して何ができるかを考えます。
GUIであるエクスプローラの操作を想像すれば何がAPIに必要かがわかります。
処理 | ファイル | ディレクトリ | 説明 |
---|---|---|---|
新規作成 (create) |
〇 | 〇 | ファイルを新しく作成する。 (ファイルの内容を書き込む事とは別) ディレクトリを新しく作成する。 |
複製 (copy) |
〇 | 〇 | ファイルを複製する。 ディレクトリ階層を複製する。 ディレクトリ配下のファイル、ディレクトリを全て複製する。 (ディレクトリが同一階層の場合、名称を別にする必要性) |
名称変更 (rename) |
〇 | 〇 | ファイル名を変更する ディレクトリ名を変更する。 同一階層に同じ名称が存在しない事。 |
移動 (move) |
〇 | 〇 | ファイルを別のディレクトリへ移動する。 ディレクトリを別ディレクトリへ移動する。 ディレクトリ配下のファイル、ディレクトリも移動する。 移動先に同一の名称のファイルまたはディレクトリが存在しない事 |
削除 (delete) |
〇 | 〇 | 不要なファイルを削除する。 不要なディレクトリを纏めて削除する。 ディレクトリ削除の場合には、 配下のファイル、ディレクトリも削除する。 |
検索 (search) |
〇 | 〇 | ファイル名が一致するファイルをディレクトリから検索する。 ディレクトリ名が一致するディレクトリを任意のディレクトリから検索する。 |
読み込み (read) |
〇 | - | 指定したファイルを読み込む。 |
書き込み (write) |
〇 | - | 指定したファイルを書き込む。 新規ファイルでない場合は、新しい内容で置き換える 又は、追加する。 |
次にOSのファイルシステムでは、ファイル及びディレクトリ作成には、
アクセス制御(権限によるアクセス許可)をするために以下の必要最低限の情報をファイル及びディレクトリに所持します。
属性 | 説明 |
---|---|
名前 | ファイル名またはディレクトリ名 |
拡張子 | ファイルの場合「.txt」などファイルの実行形式 |
作成日時 | ファイルまたはディレクトリを作成した日時 |
更新日時 | ファイルまたはディレクトリを最後に更新した日時 |
アクセス日時 | ファイルまたはディレクトリを最後にアクセスした日時 |
作成者 | ファイルまたはディレクトリを作成したアカウント |
所有者 | ファイルまたはディレクトリの所有するアカウント |
アクセス権限(アカウント) | ファイルまたはディレクトリに対するアカウント別の権限 権限とは、「変更」「読取り」「実行」「書き込み」です。 |
アクセス権限(グループ) | ファイルまたはディレクトリに対するグループ別の権限 グループとは、システムアカウント(DBやFTPなどサービス別)と ユーザアカウント(ログインできるユーザ)を意味ある集合に纏めた総称です。 権限とは、「変更」「読取り」「実行」「書き込み」です。 |
ファイルの属性 | 「読取り専用」「隠しファイル」 |
OSのファイルシステムでは、ファイル及びディレクトリの一貫性と結果の整合性を維持するために、
2つのプロセスから同一のファイル、ディレクトリに対して操作する場合には、
先に操作しているプロセスが優先され、2つ目のプロセスは、1つ目の操作が終了されるまで読取り専用でしかアクセスできません。
例えば上記図のように貴方が、Javaアプリケーションで利用するログファイルなどをエディタで開いていた場合には、
2つ目のプロセスであるJavaアプリケーションがファイルに対して、変更を伴う処理ができず、読取りしかできません。
Javaプログラムで意識する必要があるのが、共通に操作するディレクトリやファイルの操作は、並列処理で変更のタイミングが重なった場合に
どのような(例外にする、待つ、何回かトライする、キューのように順番待ちにする等)処理をするかです。
ファイルシステムの基本機能にjava.nio.file.Filesクラスのメソッドを当て込んでいきましょう。
処理 | 戻り値 | 対応メソッド | 説明 | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
新規作成 (create) |
Path | createFile (Path path, FileAttribute<?>... attrs) |
空のファイルを作成します。ファイル属性は、FileAttributeで指定します。 引数で引き渡したPathと戻り値のPathのインスタンスは同じです。 |
||||||||||
複製 (copy) |
long | copy (Path source, Path target, CopyOption... options) |
ファイルのコピーは3つあります。 3つのメソッド共にメソッドの引数は、From(コピー元)、To(コピー先)の関係です。 CopyOptionは具体的には、以下の4つがあり、0~4つ指定します。
|
||||||||||
long | copy (InputStream in, Path target, CopyOption... options) |
InputStreamの内容でtagetにファイルを作成します。 | |||||||||||
long | copy (Path source, OutputStream out) |
sourceのファイルを元にOutputStreamへ内容をコピーします。 | |||||||||||
名称変更 (rename) |
Path | move (Path source, Path target, CopyOption... options) |
sourceで指定したファイル名をtargetで指定したファイル名にします。 | ||||||||||
移動 (move) |
Path | move (Path source, Path target, CopyOption... options) |
同上と同じメソッドを利用します。 sourceで指定したディレクトリ階層のファイルを targetで指定したディレクトリ階層に移動します。 targetで指定ディレクトリは事前に作成されている必要があります。 |
||||||||||
削除 (delete) |
vold | delete (Path path) |
削除ファイルが存在しないとNoSuchFileExceptionをthrowします。 | ||||||||||
boolean | deleteIfExists (Path path) |
削除ファイルが存在しなかった場合には、戻り値にfalseを返します。 削除ファイルが存在した場合で削除できた場合には、trueを返します。 |
|||||||||||
検索 (search) |
Stream<Path> | Java8walk ( Path start , FileVisitOption... options ) |
開始位置startを起点として、 startディレクトリ配下のディレクトリと ファイルを網羅したStream<Path>を返します。 ディレクトリ数が多い場合には、次のメソッドを利用します。 オプションは、FOLLOW_LINKSがあります。 このオプションを指定するとシンボリックリンクをたどります。 |
||||||||||
Stream<Path> | Java8walk ( Path start , int MaxDepth , FileVisitOption... options) |
開始位置startを起点として、 startディレクトリ配下のディレクトリ ファイルを網羅したStream<Path>を返します。 ただし、探索される階層の深さはMaxDepthで指定した階層までです。 ディレクトリ数が多く、制限を設ける場合には、こちらを利用します。 |
|||||||||||
Stream<Path> | Java8find (Path start, int maxDepth, BiPredicate<Path,BasicFileAttributes< matcher, FileVisitOption... options) |
開始位置startを起点として、 startディレクトリ配下のディレクトリと ファイルをmatcherに該当した対象を戻り値に含ませる。 walkは、指定した階層以下全ての一覧を取得して何か操作する場合に、 適しているといえます。 逆にfindは、子階層の一覧情報は不要で、指定した検索条件に該当します。 対象のみを取得したい場合には,walkより効率が良いです。 |
|||||||||||
Path | walkFileTree (Path start, FileVisitor<? super Path> visitor) |
開始位置startを起点として、 startディレクトリ配下のディレクトリと ファイルを探索する。 探索条件は、FileVisitorを継承したクラスを作成し、 オーバライドしたメソッドに比較条件などを記載します。 Java8が利用できないときの方式 読み取る階層の深さの上限を決めるインターフェイスもあります。 |
|||||||||||
読み込み (read) |
BufferdReader | newBufferedReader (Path path, Charset cs) |
指定したファイルと文字コードから、 ファイルを読取り用に開き、BufferedReaderインスタンスを生成します。 |
||||||||||
List<String> | Java8readAllLines (Path path, Charset cs) |
指定したファイルと文字コードから、 行単位の文字列を戻り値のListに格納します。 大きなサイズのファイルを読み取る場合には、 メモリを圧迫させる可能性があります。 その場合には、newBufferedReaderを利用して下さい。 |
|||||||||||
Stream<String> | Java8lines (Path path, Charset cs) |
指定したファイルと文字コードから、 行単位の文字列をStreamに格納します。 大きなサイズのファイルを読み取る場合には、 メモリを圧迫させる可能性があります。 その場合には、newBufferedReaderを利用して下さい。 try-with-resources構文を利用します。 |
|||||||||||
書き込み> (write) |
BufferdReader | newBufferedWriter (Path path, Charset cs, OpenOption... options) |
指定したファイルと文字コードから、 書き込み用のBufferedReaderインスタンスを生成します。 StandardOpenOptionを任意に指定します。 |
||||||||||
Path | write (Path path, Iterable<? extends CharSequence> lines, Charset cs, OpenOption... options) |
指定したパス、文字コード、OpenOption のファイルに対して、linesの文字列リストを全て出力します。 |
OpenOption | 説明 |
---|---|
APPEND | ファイルがWRITE用に開かれた場合、 バイトはファイルの先頭ではなく最後に書き込まれます。td> |
CREATE | ファイルが存在しない場合は 新しいファイルを作成します。 |
CREATE_NEW | 新しいファイルを作成し、 ファイルがすでに存在する場合は失敗します。 |
DELETE_ON_CLOSE | 閉じるときに削除します。 |
DSYNC | ファイルの内容の更新は、基本となる記憶装置に 同期的に書き込まれることを必要とします。 |
READ | 読取り専用でファイルを開きます |
SPARSE | スパース・ファイルです。 |
SYNC | ファイルの内容またはメタデータの更新は、 基本となる記憶装置に同期的に書き込まれることを必要とします。 |
TRUNCATE_EXISTING | ファイルがすでに存在し、それがWRITE用に開かれた場合、 その長さが0に切り詰められます。 |
WRITE | 書込みアクセス用に開きます。 |
java.nio.file.Filesの挙動を確認するためのサンプルを説明します。
サンプルのメンバメソッド
private static final Logger log = Logger.getLogger( JavaFilesSample.class.getName() );
//プロジェクトパス
private Path projectPath = Paths.get( "C:/projects/education" );
java.util.logging.Loggerを利用しています。System.out.prinltnで全て記述しても構いません。
プロジェクトのルートパスを示すprojectPathをメンバ変数として定義します。
「c:/projects/education/data/input」配下に以下のデータを用意します。ダウンロードからサンプルデータとサンプルは容易しています。
java.io.file.Files確認系メソッドのサンプル
Path path = projectPath.resolve("data/input/sample_data.txt");
Path path2 = projectPath.resolve("data/input/sample_data2.txt");
log.info("path.toString:" + path.toString() );
log.info("path2.toString:" + path2.toString() );
log.info("Files.exists( path ) is " + Files.exists( path ) );
log.info("Files.nonExists( path ) is " + Files.notExists( path ) );
log.info("Files.isDirectory( path ) is " + Files.isDirectory( path ) );
log.info("Files.isExecutable( path ):" + Files.isExecutable( path ) );
log.info("Files.isReadable( path ):" + Files.isReadable( path ) );
//何をもって通常ファイルとする?
log.info("Files.isRegularFile( path ):" + Files.isReadable( path ) );
log.info("Files.isSymbolicLink( path ):" + Files.isSymbolicLink( path ) );
log.info("Files.isWritable( path ):" + Files.isWritable( path ) );
try {
log.info("Files.size( path ):" + Files.size( path ) );
} catch (IOException e) {
log.log( Level.SEVERE, "ファイル「{0}」に対するsize処理でエラーが発生しました。",
new String[]{ path.toString()} );
log.log( Level.SEVERE, "例外内容:", e );
}
try {
log.info("Files.isHidden( path ):" + Files.isHidden( path ) );
} catch (IOException e) {
log.log( Level.SEVERE, "ファイル「{0}」に対するisHidden処理でエラーが発生しました。",
new String[]{ path.toString()} );
log.log( Level.SEVERE, "例外内容:", e );
}
try {
log.info("Files.isSameFile( path , path2 ) is " + Files.isSameFile( path , path2 ) );
} catch (IOException e) {
String[] params = new String[2];
params[0] = path.toString();
params[1] = path2.toString();
log.log( Level.SEVERE, "2つのファイル「{0}」「{1}」の比較でエラーが発生しました。", params );
log.log( Level.SEVERE, "例外内容:", e );
}
log.info("Files.isSymbolicLink( path ) is " + Files.isSymbolicLink( path ) );
ファイルの新規作成サンプル
Path newFilePath = projectPath.resolve("data/output/new_empty.txt");
Path resultPath = null;
try {
//ファイルが存在するとエラーになります。
resultPath = Files.createFile( newFilePath );
} catch (IOException e) {
String path = newFilePath.toString();
log.log( Level.SEVERE, "ファイル「{0}」の新規作成処理でエラーが発生しました。", new String[]{ path } );
log.log( Level.SEVERE, "例外内容:", e );
}
ファイルの複製サンプル
Path fromPath = projectPath.resolve("data/input/sample_data.txt");
Path toPath = projectPath.resolve("data/output/sample_data.txt");
try {
/*
* toPathにファイルが存在した場合には、上書きするオプションを指定しています。
* このオプションを指定しない場合、copy先にファイルが存在する場合には、
* java.nio.file.FileAlreadyExistsExceptionがthrowされます。
*/
Path resultPath = Files.copy( fromPath , toPath , StandardCopyOption.REPLACE_EXISTING);
} catch (FileAlreadyExistsException e) {
log.log( Level.SEVERE, "ファイル「{0}」は存在します。", toPath.toString() );
log.log( Level.SEVERE, "例外内容:", e );
} catch (IOException e) {
String[] params = new String[2];
params[0] = fromPath.toString();
params[1] = toPath.toString();
log.log( Level.SEVERE, "ファイル「{0}」から「{1}」へのコピー処理でエラーが発生しました。", params );
log.log( Level.SEVERE, "例外内容:", e );
}
ファイルの複製サンプル
Path toPath = projectPath.resolve("data/output/logging_copy.properties");
//JavaFilesSampleのクラス名は貴方が作成しているサンプルクラスのクラス名を付与して下さい。
try ( InputStream is = JavaFilesSample.class.getClassLoader().getResourceAsStream( "logging.properties"); ) {
long resultLong = Files.copy( is , toPath , StandardCopyOption.REPLACE_EXISTING);
log.info("result copy long result:" + resultLong);
} catch (IOException e) {
String[] params = new String[2];
params[0] = "classpath内のlogging.properties";
params[1] = toPath.toString();
log.log( Level.SEVERE, "ファイル「{0}」から「{1}」へのコピー処理でエラーが発生しました。", params );
log.log( Level.SEVERE, "例外内容:", e );
}
inputStreamを利用したサンプルです。クラスパス上のファイルを読み取り指定先のパスにコピーしています。
ファイルの複製サンプル
Path fromPath = projectPath.resolve("data/input/sample_data.txt");
Path toPath = projectPath.resolve("data/output/sample_data3.txt");
try ( OutputStream os = Files.newOutputStream( toPath ) ){
long resultLong = Files.copy( fromPath , os );
log.info("result copy long result:" + resultLong);
} catch (IOException e) {
String[] params = new String[2];
params[0] = fromPath.toString();
params[1] = toPath.toString();
log.log( Level.SEVERE, "ファイル「{0}」から「{1}」へのコピー処理でエラーが発生しました。", params );
log.log( Level.SEVERE, "例外内容:", e );
}
OutputStreamを利用したサンプルです。
ファイル名変更のサンプル(ファイル名変更)
Path fromPath = projectPath.resolve("data/input/rename_before.txt");
Path toPath = projectPath.resolve("data/input/rename_after.txt");
try {
Path resultPath = Files.move(fromPath, toPath );
} catch (IOException e) {
String[] params = new String[2];
params[0] = fromPath.toString();
params[1] = toPath.toString();
log.log( Level.SEVERE, "ファイル「{0}」から「{1}」への名称変更処理でエラーが発生しました。", params );
log.log( Level.SEVERE, "例外内容:", e );
}
ファイル名のみ変更するサンプルです。
ファイル移動のサンプル(ディレクトリ移動)
Path fromPath = projectPath.resolve("data/input/move_before.txt");
Path toPathDir = projectPath.resolve("data/input/moveto");
Path toPath = toPathDir.resolve("move_before.txt");
try {
//このメソッドを実行することで、指定したディレクトリ階層が全て作成されます。
//Files.createDirectories( toPathDir );
/**
* toPathの保存先のディレクトリは存在する必要があります。
*/
Path resultPath = Files.move(fromPath, toPath );
checkResult( toPath , resultPath );
} catch (FileAlreadyExistsException e) {
log.log( Level.SEVERE, "ファイル「{0}」は存在します。", toPath.toString() );
log.log( Level.SEVERE, "例外内容:", e );
} catch (IOException e) {
String[] params = new String[2];
params[0] = fromPath.toString();
params[1] = toPath.toString();
log.log( Level.SEVERE, "ファイル「{0}」から「{1}」への移動処理でエラーが発生しました。", params );
log.log( Level.SEVERE, "例外内容:", e );
}
ファイルのディレクトリを移動するサンプルです。
ファイル削除のサンプル
Path deletePath = projectPath.resolve("data/input/delete/delete1.txt");
try {
Files.delete( deletePath );
} catch (NoSuchFileException e) {
log.log( Level.SEVERE, "削除ファイル{0}」が存在しません", new String[]{ deletePath.toString() } );
log.log( Level.SEVERE, "例外内容:", e );
} catch (IOException e) {
log.log( Level.SEVERE, "ファイル「{0}」の削除処理でエラーが発生しました。", new String[]{ deletePath.toString() } );
log.log( Level.SEVERE, "例外内容:", e );
}
指定したファイルを削除するサンプルです。
ファイル削除のサンプル-deleteIfExists
Path deletePath = projectPath.resolve("data/input/delete/delete1.txt");
Path deletePath2 = projectPath.resolve("data/input/delete/delete2.txt");
try {
//前のメソッドで既に削除されているケース
boolean result1 = Files.deleteIfExists( deletePath );
//ファイルが存在するケース
boolean result2 = Files.deleteIfExists( deletePath2 );
log.info("元々削除されている場合の結果:=" + result1);
log.info("ファイルが存在して削除する場合の結果:=" + result2);
} catch (NoSuchFileException e) {
log.log( Level.SEVERE, "削除ファイル{0}」が存在しません", new String[]{ deletePath.toString() } );
log.log( Level.SEVERE, "例外内容:", e );
} catch (IOException e) {
log.log( Level.SEVERE, "ファイル「{0}」の削除処理でエラーが発生しました。", new String[]{ deletePath.toString() } );
log.log( Level.SEVERE, "例外内容:", e );
}
指定したファイルが存在した場合にファイルを削除するサンプルです。
ファイル検索のサンプル-walk(Path, java.nio.file.FileVisitOption...)
Path target = projectPath.resolve("src");
/*
* 探索する階層の深さを制限する場合には、階層数を指定する場合
*/
//try ( Stream<Path> stream = Files.walk( target , 5) ) {
try ( Stream<Path> stream = Files.walk( target ) ) {
/*
* 指定したディレクトリ階層とその配下全てのディレクトリとファイルを出力します。
* 出力するとStreamは閉じられます。
*/
//stream.forEach( System.out::println );
/*
* 拡張子がJavaのファイルだけ列挙する
* Java8のラムダ式利用
*
* Optional<Path> optPaths = stream
* .filter( entry -> entry.getFileName().toString().endsWith(".java") );
*/
//Java8から利用可能 ラムダ式利用
Optional<Path> optPath = stream
.filter( entry -> entry.getFileName().toString().equals("JavaFilesSample.java") )
.findFirst();
if( optPath.isPresent() ){
Path resultPath = optPath.get();
log.info("JavaFileSample.java Find... ");
log.info( resultPath.toString() );
}else{
log.info("JavaFileSample.java ファイルは見つかりませんでした" );
}
log.info("---- END walkSearchFile ----" );
} catch (IOException e) {
log.log( Level.SEVERE, "ファイル「{0}」のファイル検索(walk)処理でエラーが発生しました。", new String[]{ target.toString() } );
log.log( Level.SEVERE, "例外内容:", e );
}
「c:/projects/education/src」配下の「JavaFilesSample.java」ファイルを検索しています。
ファイルをあるディレクトリ階層から検索する場合には、findメソッドの方が効率が良いです。
上記例では、walkメソッドが、src配下のディレクトリ、ファイルをstreamにかき集めてから、stream.filterで再度、
ループ構文で対象のファイルを検索しているからです。
コメント行にあるように探索するディレクトリ階層の上限を決められます。
ファイル検索のサンプル-find(Path, int, java.util.function.BiPredicate, java.nio.file.FileVisitOption...)
Path target = projectPath.resolve("src");
//Integer.MAX_VALUEは階層数が無制限で探索することを意味します。
//Java8から利用可能 ラムダ式利用
try ( Stream<Path> stream = Files.find( target , Integer.MAX_VALUE ,
(file, attrs) -> file.getFileName().toString().equals("JavaFilesSample.java") ) ) {
log.info("JavaFileSample.java Find... ");
stream.forEach( System.out::println );
log.info("---- END findFile ----" );
} catch (IOException e) {
log.log( Level.SEVERE, "ファイル「{0}」のファイル検索(find)処理でエラーが発生しました。",
new String[]{ target.toString() } );
log.log( Level.SEVERE, "例外内容:", e );
}
「c:/projects/education/src」配下の「JavaFilesSample.java」ファイルを検索しています。
walkと動きが異なるのが、「file.getFileName().toString().equals("JavaFilesSample.java")」を関数として引渡し、
ディレクトリ階層を探索時に関数で指定した内容に合致するファイルをStreamに格納しています。
そのため、処理結果は絞り込まれた結果のみが格納され、ループの処理数が減ります。
このメソッドは、Java8らしい構文、try-with-resources、ラムダ式、Streamが利用されています。
ファイル検索のサンプル-walkFileTree(Path, FileVisitor)
Path target = projectPath.resolve("src");
List<Path> resultList = new ArrayList<Path>();
try {
Files.walkFileTree(target, new FileVisitor<Path>() {
// Print information about
// each type of file.
@Override
public FileVisitResult visitFile(Path file,
BasicFileAttributes attr) {
if ( file.getFileName().toString().equals("JavaFilesSample.java") ) {
resultList.add( file );
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir,
IOException exc) {
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFileFailed(Path file,
IOException exc) {
System.err.println(exc);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult preVisitDirectory(java.nio.file.Path dir, BasicFileAttributes attrs)
throws IOException {
// TODO 自動生成されたメソッド・スタブ
return FileVisitResult.CONTINUE;
}
} );
log.info( "検索ディレクトリ:" + target.toString() );
log.info( "検索ファイル:JavaFilesSample.java" );
log.info( "--- walkFileTree結果 START --- " );
for( Path path : resultList){
log.info( path.toString() );
}
log.info( "--- walkFileTree結果 END --- " );
} catch (IOException e) {
log.log( Level.SEVERE, "ファイル「{0}」のファイル検索(walkFreeTree)処理でエラーが発生しました。", new String[]{ target.toString() } );
log.log( Level.SEVERE, "例外内容:", e );
}
「c:/projects/education/src」配下の「JavaFilesSample.java」ファイルを検索しています。
walkFreeTreeメソッドは、Java7用のメソッドとして捉えて良いでしょう。
Java8の利用とラムダ式が許可された開発現場では、findまたはwalkメソッドの利用頻度が高いでしょう。
ファイル読取りのサンプル-newBufferedReader(Path, Charset)
Path path = projectPath.resolve("data/input/sample_data.txt");
//こちらは日本では利用しない方が良い
//try( BufferedReader br = Files.newBufferedReader( path ) ){
try( BufferedReader br = Files.newBufferedReader( path , Charset.forName("UTF-8") ) ){
String line = null;
log.info( path.toString() + "ファイルの読取 START");
while ( ( line = br.readLine() ) !=null){
log.info( line );
}
log.info( "---- ファイルの読取 END ----");
} catch (IOException e) {
log.log( Level.SEVERE, "ファイル「{0}」のファイル読取処理でエラーが発生しました。", new String[]{ path.toString() } );
log.log( Level.SEVERE, "例外内容:", e );
}
「c:/projects/education/data/input/sample_data.txt」を読み込みログに出力しています。
テキストファイルの読み込みがJava8前の方法より10数行コーディングが減っているはずです。
Java8のプラットフォームでは、文字ファイルの読み込みにはこのメソッドを推奨します。
ファイル読取りのサンプル-readAllLines(Path, Charset)
Path path = projectPath.resolve("data/input/sample_data.txt");
//読取りが終了又は例外発生時にcloseもしてくれる
List<String> resultList;
try {
resultList = Files.readAllLines( path, Charset.forName("UTF-8") );
log.info( path.toString() + "ファイルの読取[readAllLines] START");
for( String line : resultList ){
log.info( line );
}
log.info( "---- ファイルの読取 END ----");
} catch (IOException e) {
log.log( Level.SEVERE, "ファイル「{0}」のファイル読取処理でエラーが発生しました。", new String[]{ path.toString() } );
log.log( Level.SEVERE, "例外内容:", e );
}
「c:/projects/education/data/input/sample_data.txt」を読み込みログに出力しています。
newBufferedReaderの違いは、メソッドが終了した段階でファイルの1行がString型のオブジェクトのインスタンスとして生成されます。
それが全行分のため、ファイルサイズが大きいファイルの読み込みには不適切なメソッドです。
ファイル行数が数十行で1行のサイズも100文字を超えない程度なら簡易に読み取るためには良いと思います。
ファイル読取りのサンプル-lines(Path, Charset)
//こちらは日本では利用しない方が良い
//try ( Stream<String> stream = Files.lines( path ) ){
//読取りが終了又は例外発生時にcloseもしてくれる
try ( Stream<String> stream = Files.lines( path , Charset.forName("UTF-8") ) ){
log.info( path.toString() + "ファイルの読取[lines] START");
stream.forEach( System.out::println );
log.info( "---- ファイルの読取 END ----");
} catch (IOException e) {
log.log( Level.SEVERE, "ファイル「{0}」のファイル読取処理(lines)でエラーが発生しました。", new String[]{ path.toString() } );
log.log( Level.SEVERE, "例外内容:", e );
}
「c:/projects/education/data/input/sample_data.txt」を読み込みログに出力しています。
違いはラムダ式のためのStreamオブジェクトを戻り値として利用している点です。
Stringオブジェクトが行数分できている点は、readAllLinesと変わりありません。
そのため、ファイルサイズが大きいファイルの読み込みには不適切なメソッドです
ファイル書き込みのサンプル-newBufferedWriter(Path path, Charset cs, OpenOption... options)
//存在しないファイル
Path path = projectPath.resolve("data/output/output1.txt");
//こちらは日本では利用しない方が良い
//try( BufferedReader br = Files.newBufferedWriter( path ) ){
//ファイルが既に存在している場合には、先のファイルの内容は上書きされます。
try( BufferedWriter bw = Files.newBufferedWriter( path , Charset.forName("UTF-8") , StandardOpenOption.CREATE ) ){
log.info( path.toString() + "ファイルの書き込み START");
bw.write("指定した文字コード:UTF-8");
bw.newLine();
bw.write("改行コードはnewLine任せ。");
bw.newLine();
bw.write("書き込み終了");
log.info( "---- ファイルの書き込み END ----");
} catch (IOException e) {
log.log( Level.SEVERE, "ファイル「{0}」のファイル書き込み処理でエラーが発生しました。", new String[]{ path.toString() } );
log.log( Level.SEVERE, "例外内容:", e );
}
「c:/projects/education/data/output/output1.txt」にwriteメソッドを利用して文字をファイルに出力しています。
OpenOptionを指定することで、きめ細やかな制御が可能です。
OpenOptionは、カンマ区切りで複数引き渡す事が可能です。
Java8プラットフォームでは、文字ストリームの書き込みはこのnewBufferedWriterを利用をお勧めします。
ファイル書き込みのサンプル-lines(Path, Charset)
//存在しないファイル
Path path = projectPath.resolve("data/output/output2.txt");
List<String> writeList = new ArrayList<String>();
writeList.add("FIles.writeメソッド試験結果");
writeList.add("2行目の予定");
writeList.add("最終行:合計3行の予定");
//こちらは日本では利用しない方が良い
//Files.write(path, writeList StandardOpenOption.CREATE);
//ファイルが既に存在している場合には、先のファイルの内容は上書きされます。
try{
log.info( "---- ファイルの書き込み START ----");
Files.write(path, writeList ,Charset.forName("UTF-8"), StandardOpenOption.CREATE);
log.info( "---- ファイルの書き込み END ----");
} catch (IOException e) {
log.log( Level.SEVERE, "ファイル「{0}」のファイル書き込み処理でエラーが発生しました。", new String[]{ path.toString() } );
log.log( Level.SEVERE, "例外内容:", e );
}
「c:/projects/education/data/output/output2.txt」にwriteメソッドを利用して文字をファイルに出力しています。
OpenOptionを指定することで、きめ細やかな制御が可能です。
OpenOptionは、カンマ区切りで複数引き渡す事が可能です。