boolean
、char
、byte
、short
、int
、long
、float
、double
)の値とString値のバイナリI/Oをサポートします。 すべてのデータ・ストリームは、DataInput
インタフェースとDataOutput
インタフェースのいずれかを実装します。 このセクションでは、これらのインタフェースを実装するクラスのうちもっとも広く使用されている、DataInputStream
とDataOutputStream
について取り上げます。
サンプル・プログラムのDataStreams
では、データ・ストリームを使用して、データ・レコードのセットを書き出し、それを再度読む込むという操作をしています。 各レコードは、請求書の明細に関する3つの値で構成されます。値は次の表のとおりです。
レコード内の順序 | データ型 | データの説明 | 出力メソッド | 入力メソッド | 値のサンプル |
---|---|---|---|---|---|
1 | double |
商品の単価 | DataOutputStream.writeDouble |
DataInputStream.readDouble |
19.99 |
2 | int |
個数 | DataOutputStream.writeInt |
DataInputStream.readInt |
12 |
3 | String |
商品の説明 | DataOutputStream.writeUTF |
DataInputStream.readUTF |
"Java T-Shirt" |
それでは、DataStreams
の重要なコードを見ていきましょう。 はじめに、データ・ファイルの名前とそのファイルに書き込むデータを表す定数を定義します。
static final String dataFile = "invoicedata"; static final double[] prices = { 19.99, 9.99, 15.99, 3.99, 4.99 }; static final int[] units = { 12, 8, 13, 29, 50 }; static final String[] descs = { "Java T-shirt", "Java Mug", "Duke Juggling Dolls", "Java Pin", "Java Key Chain" };
DataStreams
は、次に、出力ストリームをオープンします。 DataOutputStream
は、既存のバイト・ストリーム・オブジェクトのラッパーとしてのみ生成できます。そのため、DataStreams
では、バッファ・ストリームでラップしたファイル出力ストリーム(バイト・ストリーム)をコンストラクタに渡しています。
out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(dataFile)));
DataStreams
は、レコードを書き出し、出力ストリームをクローズします。
for (int i = 0; i < prices.length; i ++) { out.writeDouble(prices[i]); out.writeInt(units[i]); out.writeUTF(descs[i]); }
writeUTF
メソッドは、修正UTF-8形式でString
値を書き出します。修正UTF-8形式は、一般的な欧文文字を1バイトのみで表せる可変幅の文字エンコーディングです。
DataStreams
は、ここで、再度データを読み取ります。 まず、入力ストリームと、入力データを格納する変数を用意する必要があります。 DataOutputStream
と同様に、DataInputStream
は、バイト・ストリームのラッパーとして生成する必要があります。
in = new DataInputStream(new BufferedInputStream(new FileInputStream(dataFile))); double price; int unit; String desc; double total = 0.0;
DataStreams
では、ストリーム内の各レコードを読み取ってそのデータを出力できます。
try { while (true) { price = in.readDouble(); unit = in.readInt(); desc = in.readUTF(); System.out.format("You ordered %d units of %s at $%.2f%n", unit, desc, price); total += unit * price; } } catch (EOFException e) { }
DataStreams
では、ファイルの末端(EOF)に達したことを判断するために、無効な戻り値をチェックするのではなく、EOFException
をキャッチしている点に注目してください。 DataInput
メソッドのすべての実装では、戻り値ではなくEOFException
が使用されます。
また、DataStreams
では、各データ型用に特殊化されたwrite
メソッドが、それぞれ同様に特殊化されたread
メソッドと完全に対応している点にも注目してください。 この方法で出力の型と入力の型が正しく対応しているかどうかを確認するのは、プログラマの役目です。 なぜなら、入力ストリームは単純なバイナリ・データのみで構成されており、個々の値の型や、ストリーム内で個々の値が始まる位置を判断する手段がないためです。
DataStreams
では、不適切なプログラミング・テクニックが1つ使用されています。 それは、浮動小数点数を使用して金額を表していることです。 一般的に、浮動小数点は値を正確に表すのには向きません。 特に、小数に使用するのは不適切です。通常の値(0.1
など)はバイナリ表現で表せないためです。
金額に使用すべき正しい型は、java.math.BigDecimal
です。 ただし、BigDecimal
はオブジェクト型のため、データ・ストリームでは使用できません。 BigDecimal
はオブジェクト・ストリームで使用できます。オブジェクト・ストリームについては、次のセクションで説明します。