背景
Javaでファイルやディレクトリ操作をしたいと思った場合、お世話になるクラスは以下が一般的かと思います。
- java.io.File
- java.nio.Path
- java.nio.Files
- java.nio.file.Paths
Fileクラスは昔からあります。
NIO.2は、Java 7で導入されたクラスで、Fileクラスに比べて新しいです。
なので、新規で実装する場合は、NIO.2を使用したいものです。
今回は、自分がjava.io.Fileで書いたコードを、NIO.2で書き直したものを紹介します。
紹介する機能
- 指定されたディレクトリ内にファイルが存在するか
- 指定されたディレクトリを中身も含めて全削除
指定されたディレクトリ内にファイルが存在するか
java 6以前
import java.io.File;
public class Demo {
public static void main(String[] args) {
File file = new File("C:/temp/");
// ファイル名の一覧を取得し、存在チェック
if (file.listFiles().length == 0) {
System.out.println("ファイルはありません。");
} else {
System.out.println("ファイルがあります。");
}
}
}
File.listFiles()の戻り値は、File型の配列で返されます。
そのlenghで配列の長さを見て、判定するという流れです。
java 7以降
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class Demo {
public static void main(String[] args) {
Path path = Paths.get("C:/temp/");
try {
if (Files.list(path).findAny().isPresent()) {
System.out.println("ファイルはあります。");
} else {
System.out.println("ファイルはありません。");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Files.list
は、ディレクトリ内のエントリを取得してStremで返します。
findAny()
は、最初に見つけた要素をOptionalで返します。
isPresent()
は、Optionalが保持する値がnullならばfalse、nullじゃなかったらtrueを返します。
指定されたディレクトリを中身も含めて全削除
java 6以前
import java.io.File;
public class Demo {
public static void main(String[] args) {
File dir = new File("C:/temp/");
deleteDir(dir);
}
public static void deleteDir(File dir) {
if (dir.exists() && dir.isDirectory()) {
for (File child : dir.listFiles()) {
if (child.isDirectory()) {
deleteDir(child);
} else {
child.delete();
}
}
}
dir.delete();
}
}
java 8以降
注意! Streamを使用しているので、java8以降でしか動作しません。
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Comparator;
public class Demo {
public static void main(String[] args) {
Path path = Paths.get("C:/temp/");
// ディレクトリを全削除
try {
Files.walk(path).sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete);
path.toFile();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Files.walk(path)
で、IOExceptionが発生する可能性があるので、throwするかcatchで対応してください。
Files.walk(path)
は、サブディレクトリを含む一覧を取得しています。
sorted(Comparator.reverseOrder())
は、降順に並び替えます。
こうすると、ファイルが先頭にきて、ディレクトリは後ろのほうに並び替えられます。
そして、filterして抽出したPaths型をFiles型に変換し、ループで削除…ということをしています。
(ごめんなさい。うまく説明できていないかもしれません。)
下記のようにすれば、Stream<Path>
を List<Path>
に変換することができます。
.collect(Collectors.toList())
を追加するだけですが…
List<Path> list = Files.walk(path).sorted(Comparator.reverseOrder()).collect(Collectors.toList());
for (Path p : list) {
System.out.println(p);
}
おまけ
試行錯誤していたら、たまたまできた機能です。
せっかくなので、紹介します。
指定されたディレクトリ内のファイル削除
java 8以降
注意! Streamを使用しているので、java8以降でしか動作しません。
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class Demo {
public static void main(String[] args) {
Path path = Paths.get("C:/temp/");
// ディレクトリ内にあるファイルを削除(サブディレクトリは削除しない)
try {
Files.walk(path).filter(Files::isRegularFile).map(Path::toFile).forEach(File::delete);
} catch (IOException e) {
e.printStackTrace();
}
}
}
.filter(Files::isRegularFile)
で、通常ファイルかどうかをチェックしています。
これでディレクトリは削除対象から除外されます。
最後に
いまだにJava 8のラムダ式、Stream、Optionalなどに慣れないです。
時代遅れ感がすごいので、なんとかしたい。けど調べれば調べるほど分からなくなって沼にハマっていきます…