入出力操作

1. 入出力の基本

Javaの入出力(I/O)は、データの読み書きを行うための機能です。コンソール入出力、ファイル操作、ネットワーク通信など様々な場面で使用されます。

標準入出力


import java.util.Scanner;

public class StandardIOExample {
    public static void main(String[] args) {
        // 標準出力
        System.out.println("こんにちは!名前を入力してください:");
        
        // 標準入力
        Scanner scanner = new Scanner(System.in);
        String name = scanner.nextLine();
        
        System.out.println("ようこそ、" + name + "さん!");
        
        // Scannerを閉じる
        scanner.close();
    }
}
            

System.out, System.in, System.err

  • System.out: 標準出力ストリーム(コンソールに出力)
  • System.in: 標準入力ストリーム(キーボードからの入力)
  • System.err: 標準エラー出力ストリーム(エラーメッセージ用)

2. ファイル入出力

Javaでは、ファイルの読み書きを行うための様々なクラスが提供されています。

ファイルの読み込み


import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class FileReadExample {
    public static void main(String[] args) {
        // try-with-resourcesを使用してリソースを自動的に閉じる
        try (BufferedReader reader = new BufferedReader(new FileReader("sample.txt"))) {
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            System.err.println("ファイル読み込みエラー: " + e.getMessage());
        }
    }
}
            

ファイルの書き込み


import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class FileWriteExample {
    public static void main(String[] args) {
        try (BufferedWriter writer = new BufferedWriter(new FileWriter("output.txt"))) {
            writer.write("これはファイルに書き込まれるテキストです。");
            writer.newLine(); // 改行
            writer.write("2行目のテキストです。");
        } catch (IOException e) {
            System.err.println("ファイル書き込みエラー: " + e.getMessage());
        }
        
        System.out.println("ファイルへの書き込みが完了しました。");
    }
}
            

3. ストリーム

Javaのストリームは、データの連続的な流れを表現します。入力ストリームはデータを読み込み、出力ストリームはデータを書き込みます。

バイトストリーム

バイナリデータを扱うためのストリームです。

  • InputStream: バイトデータを読み込むための抽象クラス
  • OutputStream: バイトデータを書き込むための抽象クラス
  • 具体的な実装: FileInputStream, FileOutputStream, ByteArrayInputStream, ByteArrayOutputStream など

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class ByteStreamExample {
    public static void main(String[] args) {
        // ファイルのコピー
        try (FileInputStream in = new FileInputStream("source.jpg");
             FileOutputStream out = new FileOutputStream("copy.jpg")) {
            
            byte[] buffer = new byte[1024];
            int bytesRead;
            
            // バッファを使用して読み書き
            while ((bytesRead = in.read(buffer)) != -1) {
                out.write(buffer, 0, bytesRead);
            }
            
            System.out.println("ファイルのコピーが完了しました。");
        } catch (IOException e) {
            System.err.println("ファイル操作エラー: " + e.getMessage());
        }
    }
}
            

4. リーダーとライター

文字データを扱うためのクラスです。文字エンコーディングを適切に処理します。

文字ストリーム

  • Reader: 文字データを読み込むための抽象クラス
  • Writer: 文字データを書き込むための抽象クラス
  • 具体的な実装: FileReader, FileWriter, StringReader, StringWriter など

バッファリング

BufferedReader や BufferedWriter を使用することで、I/O操作のパフォーマンスを向上させることができます。


import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class CharacterStreamExample {
    public static void main(String[] args) {
        // テキストファイルのコピー(文字エンコーディングを考慮)
        try (BufferedReader reader = new BufferedReader(new FileReader("source.txt"));
             BufferedWriter writer = new BufferedWriter(new FileWriter("copy.txt"))) {
            
            String line;
            while ((line = reader.readLine()) != null) {
                writer.write(line);
                writer.newLine(); // 改行を追加
            }
            
            System.out.println("テキストファイルのコピーが完了しました。");
        } catch (IOException e) {
            System.err.println("ファイル操作エラー: " + e.getMessage());
        }
    }
}
            

5. NIO(New I/O)

Java NIOは、従来のI/O APIを拡張し、高性能なI/O操作を提供します。チャネル、バッファ、セレクタなどの概念が導入されています。

Path と Files


import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.io.IOException;

public class NIOExample {
    public static void main(String[] args) {
        try {
            // ファイルパスの作成
            Path source = Paths.get("source.txt");
            Path target = Paths.get("target.txt");
            
            // ファイルのコピー
            Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
            
            // ファイルの内容を一度に読み込む
            String content = Files.readString(source);
            System.out.println("ファイルの内容:\n" + content);
            
            // ファイルに書き込む
            Files.writeString(Paths.get("output.txt"), "NIOを使った書き込みテスト");
            
            System.out.println("NIO操作が完了しました。");
        } catch (IOException e) {
            System.err.println("NIO操作エラー: " + e.getMessage());
        }
    }
}
            

チャネルとバッファ


import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

public class ChannelBufferExample {
    public static void main(String[] args) {
        Path filePath = Paths.get("channel_test.txt");
        
        // ファイルへの書き込み
        try (FileChannel channel = FileChannel.open(filePath, 
                StandardOpenOption.CREATE, StandardOpenOption.WRITE)) {
            
            String text = "NIOチャネルとバッファのテスト";
            ByteBuffer buffer = ByteBuffer.wrap(text.getBytes());
            
            channel.write(buffer);
            System.out.println("ファイルへの書き込みが完了しました。");
            
        } catch (IOException e) {
            System.err.println("チャネル操作エラー: " + e.getMessage());
        }
        
        // ファイルからの読み込み
        try (FileChannel channel = FileChannel.open(filePath, StandardOpenOption.READ)) {
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            
            int bytesRead = channel.read(buffer);
            buffer.flip(); // 読み込みモードから書き込みモードへ切り替え
            
            byte[] bytes = new byte[bytesRead];
            buffer.get(bytes);
            String content = new String(bytes);
            
            System.out.println("読み込んだ内容: " + content);
            
        } catch (IOException e) {
            System.err.println("チャネル操作エラー: " + e.getMessage());
        }
    }
}
            

6. シリアライゼーション

オブジェクトをバイト列に変換(シリアライズ)し、後で復元(デシリアライズ)する機能です。オブジェクトの永続化やネットワーク転送に使用されます。

Serializableインターフェース


import java.io.*;

// シリアライズ可能なクラス
class Person implements Serializable {
    private static final long serialVersionUID = 1L; // バージョン管理用
    
    private String name;
    private int age;
    private transient String password; // transientフィールドはシリアライズされない
    
    public Person(String name, int age, String password) {
        this.name = name;
        this.age = age;
        this.password = password;
    }
    
    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + ", password=" + password + "]";
    }
}

public class SerializationExample {
    public static void main(String[] args) {
        Person person = new Person("山田太郎", 30, "secret123");
        
        // オブジェクトのシリアライズ
        try (ObjectOutputStream out = new ObjectOutputStream(
                new FileOutputStream("person.ser"))) {
            
            out.writeObject(person);
            System.out.println("オブジェクトをシリアライズしました。");
            
        } catch (IOException e) {
            System.err.println("シリアライズエラー: " + e.getMessage());
        }
        
        // オブジェクトのデシリアライズ
        try (ObjectInputStream in = new ObjectInputStream(
                new FileInputStream("person.ser"))) {
            
            Person restoredPerson = (Person) in.readObject();
            System.out.println("復元されたオブジェクト: " + restoredPerson);
            // 注意: passwordフィールドはtransientなのでnullになる
            
        } catch (IOException | ClassNotFoundException e) {
            System.err.println("デシリアライズエラー: " + e.getMessage());
        }
    }
}
            

7. 練習問題

問題1: ファイル操作

テキストファイルを読み込み、各行の単語数をカウントして結果を別のファイルに書き込むプログラムを作成してください。

問題2: バイナリファイルのコピー

コマンドライン引数で指定された2つのファイルパスを使用して、1つ目のファイルを2つ目のファイルにコピーするプログラムを作成してください。NIOを使用して実装してください。

問題3: シリアライゼーション

学生情報(名前、学生番号、成績)を管理するクラスを作成し、複数の学生オブジェクトをリストに追加してファイルにシリアライズしてください。その後、ファイルからデシリアライズして学生情報を表示するプログラムを作成してください。