javaのIO,NIOに続いて、NIO.2についておさらい!!
IO : https://qiita.com/liguofeng29/items/e08dc21b16c0057f601e
NIO : https://qiita.com/liguofeng29/items/c827af3d62f219e17755
NIO.2とは
簡単に言えば、既存のNIOを改善したものです。
- FileIOを強化した
- 非同期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 |
- 絶対パス、相対パスによって取得する結果が異なる
- sun.nio.fs.WindowsFileSystem、これによって__「プラットフォームへ依存しない」__を実現しているのね?
- 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変更を監視する仕組みである。
従来のやり方で、考えられる実装は
- 別スレッドを立ち上げて
- 状態を保存して
- 一定間隔で走査して前の状態と比較する
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();
}
- WatchServiceを生成する
- WatchServiceを登録し、監視内容も登録する
- WatchKey取得
- take() : WatchKey取得するまで待ち続ける
- poll() : WatchKey取得し、なければnull
- poll(long timeout, TimeUnit unit):timeout分待ち続ける
- 処理
- 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());