JDK 1.1 における文字ストリーム

Java Development Kit のバージョン 1.1 は文字ストリームのサポートを java.io パッケージに導入します。

このバージョン以前では、標準 I/O 機能は InputStream および OutputStream クラスとそのサブクラスを経由して、バイトストリームだけをサポートしていました。文字ストリームはバイトストリームのようなものですが、8 ビットバイトでなく 16 ビット Unicode{tm} 文字を含んでいます。これらは Reader および Writer クラスとそのサブクラスによって実装されます。Reader および Writer は、 InputStream および OutputStream と同様な操作を基本的にサポートします。異なる点は、バイトストリームメソッドがバイトまたはバイト配列上で動作するのに対して、文字ストリームは文字、文字配列、文字列上で動作するという点です。

バイトストリームで使用可能なほとんどの機能は、また文字ストリームでも提供されます。これは各文字ストリームクラスの名前に反映されており、この前置は、通常対応するバイトストリームクラスと共有されています。例えば、PushbackReader というクラスがあり、これはバイトストリームでPushbackInputStreamが提供する機能と同じものを、文字ストリームでも提供します。

なぜ文字ストリームを使用するのか?

文字ストリームの大きな利点は、固有の文字エンコーディングに依存せず、そのため国際化が簡単なプログラムを書くのが容易になるという点です。

Java は、国際標準文字エンコーディングである Unicode{tm} に文字列を格納します。これはほとんど世界中の記述言語を表すことができます。しかし、代表的なユーザが読むテキストファイルは、 Unicode{tm} または ASCII にさえも必ずしも関係しないエンコーディングを使用します。そして、このようなエンコーディングは多数あります。文字ストリームは、バイトストリームと文字ストリームの間の架け橋として機能する 2 つのクラスを提供して、これらのエンコーディングを取扱う複雑さを覆い隠します。InputStreamReader クラスは文字入力ストリームを実装し、これはバイト入力ストリームからバイトを読み込み、そして指定されたエンコーディングに従って文字に変換します。同様に、OutputStreamWriter クラスは文字出力ストリームを実装し、これは指定されたエンコーディングに従って文字をバイトに変換し、そしてバイト出力ストリームに書き込みます。

文字ストリームの第 2 の利点は、潜在的にバイトストリームよりかなり効率的であることです。Java の当初のバイトストリームの実装の多くは、バイト単位の読み書き操作を指向しています。文字ストリームクラスは対照的に、バッファ単位の読み書き操作を指向します。この差異はもっと効率的なロック方式と組み合わされて、文字ストリームクラスが多くのケースでエンコーディング変換の追加されたオーバーヘッドを補完できるようにします。

API の概要

新しい文字ストリームクラスは、既存のバイトストリームクラスと java.io パッケージで併行するように設計されています。上述のように、各文字ストリームクラスの名前は、適当であれば Reader または Writer で終わり、前置は、もしあれば、対応するバイトストリームクラスと通常共有されます。次の表では、新しいクラスをまとめています; 左の列のインデントはスーパークラスとの関係を示します。

文字ストリームクラス 内容説明 対応するバイトクラス
 
Reader 文字入力ストリームの abstract クラス InputStream
    BufferedReader 入力のバッファリング、行の分解 BufferedInputStream
        LineNumberReader     行番号の追跡 LineNumberInputStream
    CharArrayReader 文字配列の読み込み ByteArrayInputStream
    InputStreamReader バイトストリームの文字ストリームへの変換 (なし)
        FileReader ファイルのバイトを文字ストリームに変換     FileInputStream
    FilterReader フィルタをかけられた文字入力の abstract クラス FilterInputStream
        PushbackReader 文字の押し戻しの許可 PushbackInputStream
    PipedReader PipedWriter の読み込み PipedInputStream
    StringReader String の読み込み StringBufferInputStream
 
Writer 文字出力ストリームの abstract クラス OutputStream
    BufferedWriter 出力のバッファリング、プラットフォームの行区切り文字の使用 BufferedOutputStream
    CharArrayWriter 文字配列への書き込み ByteArrayOutputStream
    FilterWriter フィルタをかけられた文字出力の abstract クラス FilterOutputStream
    OutputStreamWriter 文字ストリームのバイトストリームへの変換 (なし)
        FileWriter 文字ストリームのバイトファイルへの変換 FileOutputStream
    PrintWriter Writer への値とオブジェクトの印刷 PrintStream
    PipedWriter PipedReader への書き込み PipedOutputStream
    StringWriter String への書き込み (なし)

関連した変更

PrintStream

PrintStream クラスは、プラットフォームのデフォルト文字エンコーディングとプラットフォームのデフォルト行終了子を使用するよう、修正されました。こうして、各 PrintStreamOutputStreamWriter を取り込み、出力用のバイトを生成するために、このライターをとおしてすべての文字を渡します。println メソッドはプラットフォームのデフォルト行終了子を使用しますが、この終了子はシステムプロパティ line.separator によって定義され、必ずしも単一の改行文字 ('\n') ではありません。既存の write メソッドを経由して書かれたバイトとバイト配列は、ライターをとおして渡されません。

PrintStream クラスを変更する主な動機は、そうすることで、 Java プログラムを ASCII 以外のローカルエンコーディングのプラットフォーム上で書く人々にとって、System.out および System.err がより有用になるからです。換言すれば、PrintStream はデバッグでの使用および既存のコードとの互換性のために主に提供されます。そのため、次の 2 つの構築子は推奨されません:

   PrintStream(OutputStream)
   PrintStream(OutputStream, boolean)

クラス全体より構築子を推奨しないことによって、System.out および System.err をそのまま使用していてコンパイルしても、推奨しない由の警告が出なくなります。こうして、Java を丁度学んでいるプログラマ、またはデバッグの目的で System.err.println 呼び出しを挿入しようとしているプログラマは、このような警告に悩まされなくなります。他方、明示的に PrintStream を構築するコードを書いているプログラマは、そのコードをコンパイルする際、推奨しない由の警告を見ることになります。テキスト出力を生成するコードは新しい PrintWriter クラスを使用する必要があり、このクラスは文字エンコーディングの指定またはデフォルトエンコーディングの受け入れを許します。便宜のために、PrintWriter クラスは OutputStream オブジェクトを取り上げ、デフォルトエンコーディングを使用する即座の OutputStreamWriter オブジェクトを作成する構築子を提供します。

他のクラス

いくつかの既存のクラスに対して小さな変更が行われました。次の構築子とメソッドは、バイトと文字の変換を正しく行わないので、推奨されません:

String   DataInputStream.readLine()
InputStream   Runtime.getLocalizedInputStream(InputStream)
OutputStream   Runtime.getLocalizedOutputStream(OutputStream)
  StreamTokenizer(InputStream)
   String(byte ascii[], int hibyte, int offset, int count)
   String(byte ascii[], int hibyte)
void   String.getBytes(int srcBegin, int srcEnd, byte dst[], int dstBegin)

最後に、次の構築子とメソッドが追加されました:

  StreamTokenizer(Reader)
byte[]   String.getBytes()
void   Throwable.printStackTrace(PrintWriter)


コメントは java-io@java.sun.com 宛てに送ってください。 Mark Reinhold / 4 February 1997