2.

Java OutputStream入門|FileOutputStream・BufferedOutputStreamの使い方

編集
この記事の要点
  • OutputStreamバイト単位でデータを書き込むための抽象クラス(java.io.OutputStream
  • ファイル書き込みは FileOutputStream、性能改善のため BufferedOutputStream でラップするのが定石
  • テキストを書きたいときは OutputStreamWriter 経由か、直接 BufferedWriter / PrintWriter を使う
  • 使い終わったら必ず close()。Java 7 以降は try-with-resources で自動クローズ
  • 主なメソッドは write(int) / write(byte[]) / write(byte[], off, len) / flush() / close()

OutputStream とは

OutputStreamストリームAPI におけるバイト出力ストリームの抽象基底クラスです。InputStream の対になるクラスで、ファイル / ネットワーク / メモリ など、どこに書くかに関わらず「バイトの並びを書き込む」インターフェースを共通化します。

抽象クラスなので直接インスタンス化はできず、用途に応じた具象クラス(FileOutputStream / ByteArrayOutputStream / BufferedOutputStream / PrintStream など)を使います。

主な具象クラス

クラス用途
FileOutputStreamファイルにバイトを書き込む
BufferedOutputStream内部バッファでまとめ書き → 性能改善
ByteArrayOutputStreamメモリ上の byte[] に書き込む(テスト・一時バッファ)
DataOutputStreamプリミティブ型(int, double, UTF 文字列)をバイナリで書く
ObjectOutputStreamオブジェクトをシリアライズして書く
PrintStreamSystem.out でおなじみ。print/println で書く
FilterOutputStream他の OutputStream をラップするデコレータ基底

主なメソッド

メソッド説明
write(int b)1 バイト書き込む(下位 8 ビットだけ使用)
write(byte[] b)配列全体を書き込む
write(byte[] b, int off, int len)配列の指定範囲を書き込む
flush()バッファに残ったデータを実際に書き出す
close()ストリームを閉じる(自動で flush)

使用例 1: ファイルに書き込む

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

public class Sample {
    public static void main(String[] args) {
        // try-with-resources で自動 close
        try (FileOutputStream fos = new FileOutputStream("out.txt")) {
            String text = "Hello, OutputStream!\n";
            fos.write(text.getBytes("UTF-8"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

使用例 2: BufferedOutputStream でラップ

1 バイトずつ write(int) を呼ぶと毎回ディスク I/O が発生して遅くなります。BufferedOutputStream で囲むと内部バッファ(既定 8192 バイト)に溜め、満杯になったタイミングでまとめて書き出されるため、桁違いに速くなります。

import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class BufferedSample {
    public static void main(String[] args) {
        try (BufferedOutputStream bos =
                 new BufferedOutputStream(new FileOutputStream("big.bin"))) {
            for (int i = 0; i < 1_000_000; i++) {
                bos.write(i & 0xFF);
            }
            // close() 時に自動 flush されるが、明示的に呼びたい場合は:
            // bos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

使用例 3: 追記モード

FileOutputStream の 2 番目の引数 appendtrue にすると、既存ファイルの末尾に追記されます(既定は false = 上書き)。

try (FileOutputStream fos = new FileOutputStream("log.txt", true)) {
    fos.write("追記行\n".getBytes("UTF-8"));
}

使用例 4: OutputStreamWriter でテキスト書き込み

OutputStream は本来バイト用ですが、OutputStreamWriter を被せると String をエンコーディング指定で書けます。さらに BufferedWriter で囲むのが定番です。

import java.io.*;
import java.nio.charset.StandardCharsets;

try (BufferedWriter bw = new BufferedWriter(
        new OutputStreamWriter(
            new FileOutputStream("memo.txt"),
            StandardCharsets.UTF_8))) {
    bw.write("こんにちは");
    bw.newLine();
    bw.write("OutputStream の世界");
}

InputStream / Writer 系との関係

方向 / 単位バイト系文字系
入力InputStreamReader 系
出力OutputStream 系Writer 系

画像・音声・ZIP などのバイナリは OutputStream、ログ・JSON・CSV などのテキストは Writer 系を選ぶのが基本方針です。

flush() と close() の使い分け

メソッド役割
flush()バッファに溜まったデータを実体に押し出す。ストリームは開いたまま
close()flush してからストリームを閉じる。OS リソース(ファイルディスクリプタ)を解放

長時間動くサーバが「途中まで書いたログがファイルに見えない」場合、たいてい flush 忘れです。try-with-resources を使えば close 時に自動 flush されるので、原則それで足ります。

よくあるエラーと対処

症状原因 / 対処
FileNotFoundException: ... (アクセスが拒否されました)書き込み権限なし / 同名ファイルが他プロセスで開かれている
文字化けgetBytes() の引数 / OutputStreamWriter の文字コード未指定。StandardCharsets.UTF_8 を明示
書き込み内容が途中までしか出ないflush / close 忘れ。try-with-resources を使う
巨大ファイルで OOMbyte[] = readAllBytes() 等で全量メモリに載せている。チャンク単位で write(buf, 0, n) ループに置き換える

関連

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. InputStream
  2. OutputStream

最近更新/作成されたページ