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はオブジェクト・ストリームで使用できます。オブジェクト・ストリームについては、次のセクションで説明します。