InputStream
またはOutputStream
の子孫クラスです。
バイト・ストリーム・クラスには多くの種類があります。 ファイルI/Oのバイト・ストリームであるFileInputStream
およびFileOutputStream
を例に、バイト・ストリームの動作を見てみましょう。 他の種類のバイト・ストリームも使い方はほぼ同じですが、おもにコンストラクタの引数が異なります。
FileInputStream
とFileOutputStream
の使い方を理解するために、CopyBytes
というサンプル・プログラムを使用します。このプログラムでは、バイト・ストリームを使用してxanadu.txt
を1バイトずつコピーしています。
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class CopyBytes { public static void main(String[] args) throws IOException { FileInputStream in = null; FileOutputStream out = null; try { in = new FileInputStream("xanadu.txt"); out = new FileOutputStream("outagain.txt"); int c; while ((c = in.read()) != -1) { out.write(c); } } finally { if (in != null) { in.close(); } if (out != null) { out.close(); } } } }
CopyBytes
の実行時間のほとんどは、入力ストリームを1バイトずつ読み取って出力ストリームに書き込む単純なループ処理で占められます。次の図はこのループを表しています。
単純なバイト・ストリームの入出力
read()
の戻り値がint
型であることにお気づきでしょうか。 入力がバイト・ストリームであるのに、なぜread()
の戻り値はbyte
型ではないのか不思議に思われるかもしれません。 その理由は、read()
の戻り値をint
型にすることで、ストリームの最後に達した際に-1を返して呼出し元に通知できるためです。
CopyBytes
では、エラーが発生した場合でも入力ストリームと出力ストリームの両方が確実にクローズされるように、finally
ブロックを使用しています。 これにより、重大なリソース・リークを回避できます。
CopyBytes
で起こりうるエラーとして、入力ファイルと出力ファイルの両方または一方をオープンできない可能性があります。 このエラーが発生すると、オープンできなかったファイルに対応するストリーム変数は、いつまでも初期値のnull
のままになります。 そのため、CopyBytes
では、close
を呼び出す前に、各ストリーム変数にオブジェクト参照が格納されている(つまり、nullではない)ことを確認しています。
CopyBytes
は普通のプログラムに見えますが、実際には使用すべきではない、ある意味で低レベルなI/O処理をしています。 xanadu.txt
には文字データが含まれているため、もっとも望ましいアプローチは文字ストリームを使用することです(これについては次のセクションで説明します)。 また、より複雑なデータ型のためのストリームも存在します。 バイト・ストリームはもっともプリミティブなI/Oだけに使用するようにしてください。
実際には有用性の低いバイト・ストリームについて説明したのは、他のすべてのストリーム・タイプがバイト・ストリームを基に作成されているためです。