バイトストリーム


バイナリの書き込み

FileWriterクラスによる、文字列の書き込みなどは非常に便利なものでした
しかし、もしプログラムが直接利用するデータを保存したい場合
文字列であれば、読み書きするたびにデコードやエンコードをしなければいけません

そうではなく、直接整数や浮動少数を読み書きしたい場合
まず最初に、バイナリデータとしてファイルに書き込む必要があります
つまり、テキストファイルではなくバイナリファイルの生成が必要なのです

バイナリデータの書き込みは、java.ioパッケージのFileOutputStreamクラスがあります
このクラスを用いれば、byte型の配列などを自由に書き込むことができます
コンストラクタは次のものがあります

public FileOutputStream( File file ) throws IOException
public FileOutputStream( FileDescriptor fdObj )
public FileOutputStream( String name ) throws IOException
public FileOutputStream( String name, boolean append ) throws IOException

FileクラスやFileDescriptorクラスのオブジェクトを渡した場合
このクラスのメソッドはそのクラスのストリームへバイトを出力します
nameを指定した場合は、システム依存のファイル名となります

appendは、trueの場合はファイルの終端にデータが付加されます
falseであれば、ファイルを上書きします

生成したオブジェクトのストリームに書き込むにはwrite()を使います
write()メソッドは次のものがあります

public void write( byte b[] ) throws IOException
public void write( byte b[], int off, int len ) throws IOException
public native void write( int b ) throws IOException

byte配列だけを指定した場合は、その配列の終端まで書き込みます
offには、データを書き込む最初の位置(オフセット)を指定します
lenは、オフセットの位置から書き込むバイト数を指定します
intを指定した場合は、そのバイトを書き込み上位ビットは無視されます

書き込んだ後はclose()メソッドを呼び出してストリームを閉じます

public native void close() throws IOException

これは、テキストストリームと同じ考え方です
書き込んだあとは、ストリーム閉じる時にフラッシュする必要があります
import java.io.*;

class test {
	public static void main(String args[]) {
		byte ary[] = { 0x41 , 0x42 , 0x43 , 0x44 };
		try {
			FileOutputStream fos = new FileOutputStream("test.txt");
			fos.write(ary);
			fos.close();
		}
		catch(IOException e) {}
	}
}
byte型の配列 ary がバイナリファイルとして出力されます
ここで生成された test.txt ファイルを開くと「ABCD」という文字になっています
これは、バイナリデータがASCIIコードとして解釈された場合です

バイナリコードの16進数 41 はASCIIコードの 'A' になりますね
これに続いて、BC...と続いているために、テキストデータとして開くとそのようになったのです

しかしこの状態ではbyte型しか出力することができません
その他のJavaのデータ型を出力するにはDataOutputStream()クラスを用います
コンストラクタは次のようになっています

public DataOutputStream( OutputStream out )

outには、データの出力ストリームを渡します
通常ここには、FileOutputStreamのオブジェクトでよいでしょう

このクラスのメソッドを駆使することで、Javaのデータ型を出力できます
オーバーライドされたwrite()メソッド以外に、次のようなメソッドがあります

public final void writeBoolean( boolean v ) throws IOException
public final void writeByte( int v ) throws IOException
public final void writeChar( int v ) throws IOException
public final void writeDouble( double v ) throws IOException
public final void writeFloat( float v ) throws IOException
public final void writeInt( int v ) throws IOException
public final void writeLong( long v ) throws IOException
public final void writeShort( int v ) throws IOException

それぞれ、指定したパラメータのデータを出力します
wirteByte()は v の下位1バイト、writeChar()は2バイトを出力します
import java.io.*;

class test {
	public static void main(String args[]) {
		try {
			DataOutputStream dos =
				new DataOutputStream(new FileOutputStream("test.txt"));
			dos.writeBoolean(true);
			dos.writeBoolean(false);
			dos.writeInt(1023);
			dos.close();
		}
		catch(IOException e) {}
	}
}
最初の1バイトは true の値、その次の1バイトはfalseの値
そしてその後の4バイトは1023の整数値を表しています

このほかにも、文字列を出力する次のようなメソッドも存在します

public final void writeBytes( String s ) throws IOException
public final void writeChars( String s ) throws IOException
public final void writeUTF( String str ) throws IOException

writeBytes()メソッドは、指定した文字列の上位8ビットを破棄して各文字のを順に書き込みます
writeChars()は、文字列を文字配列としてwriteChar()同様に各文字を書き込みます

writeUTF()は、まず最初の2バイトに後続するバイト数を出力します
その後、文字列の各文字は UTF-8 符号化により順に出力されます


バイナリの入力

今度は、バイナリデータをバイト単位で読み込むことに挑戦しましょう
これも、基本的な考え方はこれまでの入出力と同じです

バイトの入力にはFileInputStreamクラスを用います
このクラスは次のようなコンストラクタを持っています

public FileInputStream( File file ) throws FileNotFoundException
public FileInputStream( FileDescriptor fdObj )
public FileInputStream( String name ) throws FileNotFoundException

fileには読み込むファイルを、fdObjには、読み込むファイル記述子を
nameには、システムに依存するファイル名を指定します

開いたストリームからデータを読み込むにはread()を使います

public native int read() throws IOException
public int read( byte b[] ) throws IOException
public int read( byte b[], int off, int len ) throws IOException

read()は、ファイルの現在の入力ポイントから次のデータを読み込みます
読み込んだ値は、戻り値に下位8ビットにバイトとして返ります
ファイルの終端に達した場合は -1 が返ります

byte[] には、読み込んだデータを格納するバッファを指定します
バッファを指定した場合、戻り値は読み込んだ総バイト数を返します
ファイルの終端に達した場合は‐1が返ります

offは、データの読み込みを開始するオフセットを
lenは、開始位置から読み取るバイト数を指定します
offとlenを指定していない場合は、b.lengthだけデータを読み込みます
import java.io.*;

class test {
	public static void main(String args[]) {
		try {
			FileInputStream fis = new FileInputStream("test.txt");
			System.out.println(fis.read() + fis.read());
			fis.close();
		}
		catch(IOException e) {}
	}
}
このプログラムは、test.txtファイルの先頭2バイトを読み込み
それぞれを加算した結果を標準出力へ出力します

classファイルと同じディレクトリにASCIIの AB というコードを記述した場合
16進数の83という結果(10進数で131)が出力されるでしょう

読み込み位置をスキップするskip()
ストリームに関連付けられているFileDescriptorを返すgetFD()などのメソッドもあります

さらに、Javaのデータ型としてバイナリを読み込みたいなら
DataOutputStream()に対となるDataInputStream()クラスを用います
このクラスのコンストラクタは次のようになっています

public DataInputStream( InputStream in )

inには、読み込む入力ストリームを指定します

このクラスも、DataOutputStream同様に各データ型に対応する入力メソッドがあります
これを用いれば、直接バイナリデータからJavaのデータ型として読み込むことができます

public final byte readByte() throws IOException
public final char readChar() throws IOException
public final double readDouble() throws IOException
public final float readFloat() throws IOException
public final int readInt() throws IOException
public final long readLong() throws IOException
public final short readShort() throws IOException

これらのメソッドは、入力ストリームの次のバイトからそれぞれ戻り値の型で返します
この時読み込まれるサイズは、戻り値の型で異なります
import java.io.*;

class test {
	public static void main(String args[]) {
		try {
			DataOutputStream dos = 
				new DataOutputStream(new FileOutputStream("test.txt"));
			dos.writeDouble(0.5);
			dos.close();

			DataInputStream dis = 
				new DataInputStream(new FileInputStream("test.txt"));
			System.out.println(dis.readDouble() + 0.2);
			dis.close();
		}
		catch(IOException e) {}
	}
}
このプログラムは、まず最初にDouble型のデータ 0.7 を出力しています
そのデータを格納する test.txt をDataInputStreamに読み込み
そして、今度はそれを読み込みさらに0.2を加算して標準出力に出力します



前のページへ戻る次のページへ