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

javaのNIO.2おさらい

More than 1 year has passed since last update.

javaのIO,NIOに続いて、NIO.2についておさらい!!

IO : https://qiita.com/liguofeng29/items/e08dc21b16c0057f601e
NIO : https://qiita.com/liguofeng29/items/c827af3d62f219e17755

NIO.2とは

簡単に言えば、既存のNIOを改善したものです。

  1. FileIOを強化した
  2. 非同期Channleに基づくIOを強化した

FileIO強化

コアAPI

API名 概要
Path プラットフォームへ依存しない経路を表す
Paths Pathのユーティルクラス
(Pathインスタンス取得用(get)メソッドのみだった)
Files Fileのユーティルクラス

雑談:Paths,Filesはjavaの一貫した命名ルールに従ったものですね。

  • Paths, Pathのユーティルクラス
  • Files, Fileのユーティルクラスと言いながら引数が殆どPathだった!!
  • Arrays, Arrayのユーティルクラス
  • Collections, Collectionのユーティルクラス
  • Objects, Objectのユーティルクラス

Path, Paths

Pathサンプル(markdownで取得したかった)
private static void showPath(Path path) {
    System.out.println("|取得内容|結果|");
    System.out.println("|---|---|");
    System.out.printf("|%s | %s |\r\n", "要素数", path.getNameCount());
    System.out.printf("|%s | %s |\r\n", "指定要素名", path.getName(0));
    System.out.printf("|%s | %s |\r\n", "ファイル名", path.getFileName());
    System.out.printf("|%s | %s |\r\n", "ファイルシステム名", path.getFileSystem());
    System.out.printf("|%s | %s |\r\n", "親", path.getParent());
    System.out.printf("|%s | %s |\r\n", "ルート", path.getRoot());
    System.out.printf("|%s | %s |\r\n", "絶対パスか", path.isAbsolute());
}
Path,Paths
private static void path_test() {
    // 相対パス
    Path relativePath = Paths.get(".", "NIO2", "sub", "nio2-file.txt");
    System.out.println("---- 相対パス ----");
    showPath(relativePath);
    // 絶対パス
    System.out.println("---- 絶対パス ----");
    showPath(relativePath.toAbsolutePath());
}
  • 相対パス
取得内容 結果
要素数 4
指定要素名 .
ファイル名 nio2-file.txt
ファイルシステム名 sun.nio.fs.WindowsFileSystem@6e0be858
.\NIO2\sub
ルート null
絶対パスか false
  • 絶対パス
取得内容 結果
要素数 8
指定要素名 workspace
ファイル名 nio2-file.txt
ファイルシステム名 sun.nio.fs.WindowsFileSystem@6e0be858
C:\workspace\git\java-projects\java-sample.\NIO2\sub
ルート C:\
絶対パスか true
  1. 絶対パス、相対パスによって取得する結果が異なる
  2. sun.nio.fs.WindowsFileSystem、これによって「プラットフォームへ依存しない」を実現しているのね?
  3. Paths#getからPathインスタンス取得する(File to Path, Path to Fileもできるが)

Files

Filesサンプル

nio2-src.txt
1行目、AIC
2行目、UTF-8?
3行目
Filesサンプル(markdownで取得したかった)
private static void testFiles(Path path) {
    System.out.println("|取得内容|結果|");
    System.out.println("|---|---|");
    try {
        System.out.printf("|%s | %s |\r\n", "ディレクトリか", Files.isDirectory(path));
        System.out.printf("|%s | %s |\r\n", "隠しか", Files.isHidden(path));
        System.out.printf("|%s | %s |\r\n", "ディレクトリか", Files.isWritable(path));
        System.out.printf("|%s | %s |\r\n", "サイズは", Files.size(path));
        System.out.printf("|%s | " , "ファイル内容取得");
        Files.lines(path).forEach(line -> {
            System.out.printf("%s<br>" , line);
        });
        System.out.printf("|\r\n");
        System.out.printf("|%s | " , "ディレクトリ要素取得");
        Files.list(path.getParent()).forEach(p -> {
            System.out.printf("%s<br>" , p);
        });
        System.out.printf("|\r\n");
        System.out.printf("|%s | %s |\r\n", "ストレジ容量", Files.getFileStore(path).getTotalSpace() / 1024 / 1024 / 1024 + "GB");
        System.out.printf("|%s | %s |\r\n", "利用可能容量", Files.getFileStore(path).getUsableSpace() / 1024 / 1024 / 1024 + "GB");
        System.out.printf("|%s | %s |\r\n", "未割当て容量", Files.getFileStore(path).getUnallocatedSpace() / 1024 / 1024 / 1024 + "GB");
        System.out.printf("|%s | %s |\r\n", "存在するか", Files.exists(path));
        Files.delete(path);
        System.out.printf("|%s | %s |\r\n", "削除する", "削除した");
        System.out.printf("|%s | %s |\r\n", "存在するか", Files.exists(path));
    } catch (IOException e) {
        e.printStackTrace();
    }
}
取得内容 結果
ディレクトリか false
隠しか false
ディレクトリか true
サイズは 64
ファイル内容取得 1行目、AIC
2行目、UTF-8?
3行目
ディレクトリ要素取得 .\NIO2\nio2-desc.txt
.\NIO2\nio2-src.txt
.\NIO2\sub
ストレジ容量 111GB
利用可能容量 54GB
未割当て容量 54GB
存在するか true
削除する 削除した
存在するか false

File#WalkTree

既存IOでは、再帰的な走査を自分で実装する必要があり、コードが複雑&使い勝手がよくなかった。

1.7では、Files#walkFileTreeで再帰的走査が可能になる。

callback 概要
preVisitDirectory ディレクトリアクセス前発生
visitFile ディレクトリアクセス前発生
visitFileFailed ディレクトリアクセス前発生
postVisitDirectory ディレクトリアクセス後発生
FileVisitResult 概要
CONTINUE 継続する
SKIP_SIBLINGS 継続後、該当file,directoryの兄弟階層は走査しない
SKIP_SUBTREE 継続後、該当file,directoryの子供階層は走査しない
TERMINATE walk(走査)を終了する

walkFileTreeのサンプルはあっちこっち在ったので、割愛!

Files#walk

1.8では、Files#walkが便利!

Files.walk
Files.walk(Paths.get(".", "NIO2"), FileVisitOption.FOLLOW_LINKS)
    // directoryとfile入れ替え
    .sorted(Comparator.reverseOrder())
    // 削除対象確認
    .peek(System.out::println)
    // 削除
    .forEach(path -> {
        try {
            Files.delete(path);
        } catch (IOException e) {
            e.printStackTrace();
        }
    });

ほか

WatchService

File変更を監視する仕組みである。
従来のやり方で、考えられる実装は
1. 別スレッドを立ち上げて
2. 状態を保存して
3. 一定間隔で走査して前の状態と比較する

WatchServiceを使えばファイルが簡単にできる。

WatchServiceサンプル
try {
    WatchService watchService = FileSystems.getDefault().newWatchService();
    Paths.get(".").register(
        watchService,
        StandardWatchEventKinds.ENTRY_CREATE, // CREATE監視
        StandardWatchEventKinds.ENTRY_DELETE, // DELETE監視
        StandardWatchEventKinds.ENTRY_MODIFY  // MODIFY監視
    );
    System.out.println("-----watch開始-----");
    while (true) {
        // 待ち続ける
        WatchKey key = watchService.take();
        key.pollEvents().stream()
            .forEach(
                watchEvent -> {
                    System.out.println("発生種類 : " + watchEvent.kind().name());
                    System.out.println("対象名  : " + watchEvent.context());
                });
        // 次の監視
        if (!key.reset()) {
            break;
        }
    }
} catch (IOException | InterruptedException e) {
    e.printStackTrace();
}
  1. WatchServiceを生成する
  2. WatchServiceを登録し、監視内容も登録する
  3. WatchKey取得
    • take() : WatchKey取得するまで待ち続ける
    • poll() : WatchKey取得し、なければnull
    • poll(long timeout, TimeUnit unit):timeout分待ち続ける
  4. 処理
  5. WatchKeyリセット

属性読み書き

ざっくり、FileAttributeViewを実装したもので、細かい属性を操作できるそうです。

  • AclFileAttributeView
  • BasicFileAttributeView
  • DocFileAttributeView
  • FileOnwerFileAttributeView
  • PosixFileFileAttributeView
  • UserDefinedFileAttributeView
BasicFileAttributeViewサンプル
Path path = Paths.get(".", "NIO2", "nio2-src.txt");

BasicFileAttributeView view = Files.getFileAttributeView(path, BasicFileAttributeView.class);
BasicFileAttributes attributes = view.readAttributes();

System.out.println("前回アクセス : " + attributes.lastAccessTime());
System.out.println("最新修正時刻 : " + attributes.lastModifiedTime());
Why not register and get more from Qiita?
  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
No 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
ユーザーは見つかりませんでした