はじめに
皆さん、java.io.Fileクラスとjava.nio.file.Filesクラスをご存知でしょうか。この2つを理解する事によって、ファイル操作をすることができるようになります。それでは詳しく見ていきましょう。
Fileクラスとは?
java.io.Fileはフォルダー/ファイルの情報を管理すると共に、フォルダー/ファイルを操作するための手段を提供するクラスです。具体的にPathを扱う方法はFileクラスのコンストラクタにファイル名やディレクトリ名を渡して、インスタンスを生成するとカレントディレクトリーにあるパスを扱うことができます。
File file = new File("x.text");
使用方法
ファイルの存在を確かめ、存在しなければ新しいファイルを作成する方法
まずファイルの存在を確かめる為にはexesitsメソッドを使用する必要があります。exsitsメソッドは目的のファイルが存在すればtrue、存在しなければ、falseを返します。
そして、新しいファイルを作成する為にはcreateNewFileメソッドを使用する必要があります。サンプルコードを通して、具体的に見ていきましょう。
package innerclass;
import java.io.File;
import java.io.IOException;
public class Sample {
public static void main(String[] args) throws IOException{
//「x.text」を扱えるようにする
File file = new File("x.java");
//existメソッドでファイルの存在を確かめ、存在がなければ新しいファイルを作成する
if(file.exists() == false) {
file.createNewFile();
}
//作成されたファイルの絶対パスを確認
System.out.println(file.getAbsolutePath());
}
}
下記のパスに「x.txt」が作成されました。
.../Eclipse_2020-12.app/Contents/workspace/innerclass/x.text
新規ディレクトリーを作成するの場合
mkdirsメソッドを使用しましょう。先ほどのサンプルコードのcreateFileNewメソッドの部分をmkdirsメソッドに変更して実行してみます。
File dir = new File("new");
if(dir.exists() == false) {
dir.mkdir();
}
下記のバスにnewディレクトリーが作成されました。
.../Eclipse_2020-12.app/Contents/workspace/innerclass/new
リストやディレクトリーの一覧を取得する場合
listFilesメソッドを使用します。FileクラスのlistFilesメソッドは、指定したディレクトリに含まれるファイルやディレクトリを配列として返します。
package innerclass;
import java.io.File;
import java.io.IOException;
public class Sample {
public static void main(String[] args) throws IOException{
//カレントディレクトリーへのパスを表すFileのインスタンスを作成
File dirList= new File(".");
show(dirList, "");
}
private static void show(File dir, String indent) {
//ファイルやディレクトリーの一覧を取得して変数filesに格納
File[] files = dir.listFiles();
//getNameメソッドを使用して、ファイル名やディレクトリー名をコンソールに表示
for (File file : files) {
System.out.println(indent + file.getName());
//ディレクトリーであれば、showTreeメソッドを再帰する
if(file.isDirectory()) {
show(file, indent + " ");
}
}
}
}
bin
x.text
.classpath
.settings
.project
new
src
innerclass
SampleCollector.java
SampleThrad.java
Sample.java
Man.java
NIO.2とは?
java.io.Fileクラスは設計思想が古く、ディレクトリーツリーの探索が手軽できないことや、ファイルのコピーが簡単にできないなど課題がありました。それを解決するためにJavaSE7で導入されたのがNIO.2です。特徴はファイルやディレクトリーのパスを表す機能とファイル操作の機能が完全に分離さてています。ファイルやディレクトリーのパスを表すにはjava.nio.file.Pathインターフェースを使用し、ファイルを操作するにはjava.nio.file.Filesクラスを使用します。
使用方法
ファイルやディレクトリーのパスを扱う方法
パスのインスタンスへの参照はPathを利用しやすくするためのjava.nio.file.Pathsクラスのgetメソッドを使用します。引数に目的のファイルやディレクトリへのパスを記述します。
Path path = Paths("dir/sample.text");
新しいファイルの作成
ファイルの作成はFilesクラスのcreateFileメソッドを使用します。
package innerclass;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Scanner;
public class Sample {
public static void main(String[] args) throws Exception{
System.out.print(">");
//Scannerクラスのインスタンスを作成し、キーボードから入力された文字列や数値を受け取って、処理する
Scanner scan = new Scanner(System.in);
String name = scan.nextLine();
//dirディレクトリ配下のファイル(コンソールで指定)のパスを取得
Path p = Paths.get("dir", name);
//もし指定したファイルが存在しなければ、新しくファイルを作成
if(Files.exists(p) == false) {
Files.createFile(p);
}
//最終更新日をコンソールに出力
System.out.println(Files.getLastModifiedTime(p));
//ファイルのアクセス権を調べるためのメソッド
System.out.println(Files.getPosixFilePermissions(p));
}
}
コンソールにaを入力しているのでaのファイルが作成されました。
>a
2022-04-04T11:50:59.240684Z
[OTHERS_READ, OWNER_READ, OWNER_WRITE, GROUP_READ]
ディレクトリーを作成する場合
createDirectoriesメソッドを使います。ファイル作成した時のサンプルコードのcreateFileの部分をcreateDirectoriesに置き換えてみます。
Files.createDirectory(p);
コンソールにbを入力しているのでbのディレクトリーが作成されました。
>b
2022-04-04T12:26:24.635773Z
[GROUP_READ, OWNER_READ, OTHERS_EXECUTE, OWNER_WRITE, OTHERS_READ, OWNER_EXECUTE, GROUP_EXECUTE]
親ディレクトリが存在しない時でもディレクトリを作成したい場合
createDirectoriesメソッドを使います
FIle.createDirectories(p);
既存のディレクトリー内のパスを表現する場合
Pathsクラスのgetメソッドを使用します。getメソッドは引数は2つの引数を受け取ります。1つ目は単一の文字列。2つ目は文字列の可変長引数です。可変長引数なので、いくつでも引数を渡す他に、引数なしでも可能です。
Path get(String first, String... more)
パス情報を結合したい場合
同じディレクトー内にファイルを複数作る時、コードが乱雑になってしまいます。例えば、ファイルを2つ作成したい場合は2つとも同じパスを書かないといけません。そんな時Pathsクラスのresolveメソッドを使用します。Path オブジェクトが持つパスの情報に別の Path オブジェクトが持つパス情報を結合した新しい Path オブジェクトを返します。
Path dir = Paths.get("dir","subdir");
Path file = dir.resolve(Paths.get("a.txt"));
ファイルをコピーしたい場合
Filesクラスのcopyメソッドを使用します。第1引数にコピー元へのパス、第2引数にコピー先へのパスを指定します。
package innerclass;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class Sample {
public static void main(String[] args) throws Exception{
//既存のディレクトリ内のパスを指定
Path sample = Paths .get ("dir", "sample.txt");
//指定したパスにファイルがなければ新しく作成する
if(Files.exists(sample)== false) {
Files.createFile(sample);
}
Path outFile = Paths.get("dir","sample_bk.txt");
//sample.txtをコピーする
Files.copy(sample,outFile);
}
}
その結果、sample.txtがコピーされてsample_bk.txtが作成されました。
ファイルを移動したい場合
Filesクラスのmoveメソッドを使用します。第1引数に移動元へのパス、第2引数に移動先へのパスを指定します。先ほどのコードに下記のコードを追加してみます。
Path dir = Paths.get("dir","b");
Path dest = dir.resolve(Paths.get("sample.txt"));
Files.move(sample,dest);
実行後、bフォルダーにsample.textが移動されました。
ファイル内のデータを読み込みたい場合
FilesクラスのnewBufferdReaderメソッドを使用します。
Path sample = Paths.get("sample.txt");
BufferedReader br = Files.newBufferedReader(sample);
try(br){
br.lines().forEach(System.out::println);
}
ファイル内のデータを書き込みたい場合
FilesクラスのnewBufferedWriterメソッドを使用します。
Path sample = Paths.get("sample.text);
BufferdWriter out = Files.newBufferedWriter(sample);
try(out){
out.write("こんにちは");
out.newLine();
}
追記で書き込む例
newBufferedWriterメソッドの引数に、java.nio.file.OpenOptionインターフェース型のAPPENDを指定します。
package innerclass;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Scanner;
public class Sample {
public static void main(String[] args) throws Exception{
Path sample = Paths.get ("dir","sample.txt");
if(Files.exists(sample)== false) {
Files.createFile(sample);
}
//標準入力を取得する
Scanner scan = new Scanner(System.in);
//引数にtandardOpenOption.APPENDを指定すると、追記できる
BufferedWriter out = Files.newBufferedWriter(sample,StandardOpenOption.APPEND);
try(scan; out){
System.out.print("> ");
out.write(scan.nextLine());
out.newLine();
}
BufferedReader in = Files.newBufferedReader(sample);
try(in){
in.lines().forEach(System.out::println);
}
}
}
aaaaaaを追記してみます。
そうすると、sample.textに追記されていることがわかります。
> aaaaaa
aaaaaa
ディレクトリー内のすべてのパスを取得したい場合
Filesクラスのlistメソッドを使用します。引数で渡されたディレクトリ内のディレクトリやファイルを表すPathオブジェクトの一覧をStreamオブジェクトとして戻します。
Files.list(base).forEach(System.out::println);
ディレクトリー内を再起的に処理する場合
Filesクラスのwalkメソッドを使用します。
Files
.walk(base.resolve("src"))
.forEach(System.out::println);
ディレクトリの再帰的な探索を行いたい場合
walkFileTreeメソッドを使用します。4つのタイミングで処理を実行し、それに合わせて4つの抽象メソッドが定義されている。
package innerclass;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
public class Sample {
public static void main(String[] args) throws Exception{
Path dir = Paths.get("dir","data");
if(Files.exists(dir) == false) {
Files.createDirectories(dir);
}
//resolceメソッド:パス情報にパス情報を統合する
Files.createFile(dir.resolve(Paths.get("a.text")));
Files.createFile(dir.resolve(Paths.get("b.text")));
Files.createFile(dir.resolve(Paths.get("c.text")));
Files.list(dir).forEach(System.out::println);
//dirディレクトリ内を再起的に移動しながら、該当するファイルを削除していく
Files .walkFileTree(dir,new SimpleFileVisitor<Path>() {
/*
* 本来であれば4つの抽象メソッドが必要だが、FileVisitResultクラスをオーバーライド
* する事によって必要がなくなる。
*/
@Override
public FileVisitResult visitFile(
Path file,
BasicFileAttributes attrs) throws IOException{
Files.delete(file);
//ファイルを探索を続けるためにCONTINUEを返えす
return FileVisitResult.CONTINUE;
}
});
Files.delete(dir);
System.out.println("deleted");
}
}
dir/data/a.text
dir/data/c.text
dir/data/b.text
deleted