ストリームとNIO
このレッスンでは、JavaのストリームベースIOとNIOによる低レベルファイル操作を学びます。
IOストリームアーキテクチャ
TEXT
入力ストリーム(読み取り)
InputStream(バイト入力)
├── FileInputStream(ファイル)
├── BufferedInputStream(バッファ)
├── ByteArrayInputStream(バイト配列)
└── DataInputStream(プリミティブ型)
Reader(文字入力)
├── FileReader(ファイル)
├── BufferedReader(バッファ)
└── InputStreamReader(変換)
出力ストリーム(書き込み)
OutputStream(バイト出力)
├── FileOutputStream(ファイル)
├── BufferedOutputStream(バッファ)
└── DataOutputStream(プリミティブ型)
Writer(文字出力)
├── FileWriter(ファイル)
├── BufferedWriter(バッファ)
└── OutputStreamWriter(変換)
バイトストリーム
FileInputStreamによる読み取り
JAVA
import java.io.FileInputStream;
import java.io.IOException;
public class FileInputStreamDemo {
public static void main(String[] args) {
try (FileInputStream fis = new FileInputStream("test.txt")) {
int data;
while ((data = fis.read()) != -1) {
System.out.print((char) data);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
FileOutputStreamによる書き込み
JAVA
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutputStreamDemo {
public static void main(String[] args) {
try (FileOutputStream fos = new FileOutputStream("output.txt")) {
String text = "Hello, World!";
fos.write(text.getBytes());
System.out.println("書き込み成功");
} catch (IOException e) {
e.printStackTrace();
}
}
}
例:バイトストリームによるファイルコピー
JAVA
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class ByteCopy {
public static void copy(String src, String dest) throws IOException {
try (FileInputStream fis = new FileInputStream(src);
FileOutputStream fos = new FileOutputStream(dest)) {
byte[] buffer = new byte[1024];
int length;
while ((length = fis.read(buffer)) != -1) {
fos.write(buffer, 0, length);
}
}
}
public static void main(String[] args) {
try {
copy("source.txt", "dest.txt");
System.out.println("コピー完了");
} catch (IOException e) {
e.printStackTrace();
}
}
}
バッファストリーム
バッファストリームはディスクアクセス回数を減らし、IO効率を向上させます。
BufferedInputStream/BufferedOutputStream
JAVA
import java.io.*;
public class BufferedStreamDemo {
public static void main(String[] args) throws IOException {
// 書き込み
try (BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream("buffered.txt"))) {
for (int i = 0; i < 1000; i++) {
bos.write(("Line " + i + "\n").getBytes());
}
}
// 読み取り
try (BufferedInputStream bis = new BufferedInputStream(
new FileInputStream("buffered.txt"))) {
byte[] buffer = new byte[1024];
int length;
while ((length = bis.read(buffer)) != -1) {
System.out.write(buffer, 0, length);
}
}
}
}
データストリーム
DataInputStream/DataOutputStreamはプリミティブ型を読み書きできます。
例:データストリーム
JAVA
import java.io.*;
public class DataStreamDemo {
public static void main(String[] args) throws IOException {
// 書き込み
try (DataOutputStream dos = new DataOutputStream(
new FileOutputStream("data.dat"))) {
dos.writeInt(100);
dos.writeDouble(3.14);
dos.writeUTF("Hello");
}
// 読み取り
try (DataInputStream dis = new DataInputStream(
new FileInputStream("data.dat"))) {
int i = dis.readInt();
double d = dis.readDouble();
String s = dis.readUTF();
System.out.println("int: " + i); // 100
System.out.println("double: " + d); // 3.14
System.out.println("string: " + s); // Hello
}
}
}
NIO(New IO)
Java NIOはより効率的なIO操作を提供します。
Pathインターフェース
JAVA
import java.nio.file.Path;
import java.nio.file.Paths;
public class PathDemo {
public static void main(String[] args) {
Path path = Paths.get("/home/user/test.txt");
System.out.println("ファイル名: " + path.getFileName()); // test.txt
System.out.println("親ディレクトリ: " + path.getParent()); // /home/user
System.out.println("ルート: " + path.getRoot()); // /
System.out.println("名前数: " + path.getNameCount()); // 3
}
}
Filesユーティリティクラス
JAVA
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
public class FilesDemo {
public static void main(String[] args) throws IOException {
Path path = Paths.get("test.txt");
// チェック
System.out.println("存在する: " + Files.exists(path));
System.out.println("ファイルか: " + Files.isRegularFile(path));
System.out.println("読み取り可能: " + Files.isReadable(path));
// すべての行を読み取る
List<String> lines = Files.readAllLines(path);
lines.forEach(System.out::println);
// バイト配列として読み取る
byte[] bytes = Files.readAllBytes(path);
System.out.println("サイズ: " + bytes.length);
// 書き込み
Files.write(Paths.get("output.txt"), "Hello".getBytes());
// ディレクトリ作成
Files.createDirectories(Paths.get("newdir/subdir"));
// コピー
Files.copy(Paths.get("source.txt"), Paths.get("dest.txt"));
// 移動
Files.move(Paths.get("old.txt"), Paths.get("new.txt"));
// 削除
Files.deleteIfExists(Paths.get("temp.txt"));
}
}
ファイル属性
JAVA
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileTime;
public class FileAttributes {
public static void main(String[] args) throws IOException {
Path path = Paths.get("test.txt");
BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class);
System.out.println("サイズ: " + attrs.size());
System.out.println("作成日時: " + attrs.creationTime());
System.out.println("更新日時: " + attrs.lastModifiedTime());
System.out.println("ディレクトリか: " + attrs.isDirectory());
System.out.println("ファイルか: " + attrs.isRegularFile());
}
}
ファイル走査(NIO)
JAVA
import java.io.IOException;
import java.nio.file.*;
import java.util.stream.Stream;
public class NIODirectoryWalk {
public static void main(String[] args) throws IOException {
Path dir = Paths.get(".");
// ディレクトリを一覧表示
try (Stream<Path> stream = Files.list(dir)) {
stream.forEach(path -> {
String type = Files.isDirectory(path) ? "[DIR]" : "[FILE]";
System.out.println(type + " " + path.getFileName());
});
}
// 再帰的に走査
try (Stream<Path> stream = Files.walk(dir, 3)) { // 最大3レベル
stream.forEach(path -> System.out.println(path));
}
// ファイルを検索
try (Stream<Path> stream = Files.find(dir, 10,
(path, attrs) -> attrs.isRegularFile() && path.toString().endsWith(".txt"))) {
stream.forEach(System.out::println);
}
}
}
IO vs NIO
| 特徴 | IO | NIO |
|---|---|---|
| モデル | ストリーム指向 | バッファ指向 |
| ブロッキング | ブロッキングIO | 非ブロッキングIO |
| セレクタ | なし | あり |
| API | 古い | 新しい |
選択ガイド
| シナリオ | 推奨 |
|---|---|
| 簡単なファイル読み書き | Filesユーティリティクラス |
| 大きなファイル処理 | バッファストリーム |
| 高並行ネットワーク | NIO |
| レガシーコード保守 | IOストリーム |
❓ よくある質問
Q バイトストリームと文字ストリームのどちらを選ぶべきですか?
A テキストファイルには文字ストリームを使用し、バイナリファイルにはバイトストリームを使用してください。
Q バッファストリームの利点は何ですか?
A ディスクアクセス回数を減らし、IO効率を向上させます。
Q NIOはIOより速いですか?
A 必ずしもそうではありません。NIOの主な利点は非ブロッキングとセレクタです。簡単なファイル操作では差は最小限です。
📖 まとめ
- IOストリームはバイトストリームと文字ストリームに分かれる
- バッファストリームはIO効率を向上させる
- NIOはより効率的なファイル操作を提供
- Filesユーティリティクラスはファイル操作を簡素化
📝 演習
- ファイル比較: 2つのファイルが同一かどうかを比較
- 大きなファイル処理: 大きなファイルをチャンクで読み取り、行数をカウント
- ディレクトリ同期: 1つのディレクトリを別のディレクトリに同期
次のレッスン
次のレッスンでは、正規表現とJSONを学びます — 高度な文字列処理技術。



