Help us understand the problem. What is going on with this article?

[Java]過去の自分が作成した機能をjava.io.FileからNIO.2で書き直し

背景

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などに慣れないです。
時代遅れ感がすごいので、なんとかしたい。けど調べれば調べるほど分からなくなって沼にハマっていきます…

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away