InputStream/OutputStream型
OutputStream型
データを書き出すための Stream であり,使い方は Writer
とほぼ同じです.
例えば,以下のサンプルプログラムの writeWithWriter
は
Writer型で示した典型的なWriter
の使い方です.
このwriteWithWriter
と対比して,writeWithOutputStream
を確認してください.
void writeWithWriter(File file, String message) throws IOException{
PrintWriter out = new PrintWriter(new FileWriter(file)); // (2)
// 上記の(2)の処理を区別して書くと次のような処理になる.
// FileWriter fwriter = new FileWriter(file);
// PrintWriter out = new PrintWriter(fwriter);
out.print(message);
out.close();
}
void writeWithOutputStream(File file, String message) throws IOException{
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file)); // (3)
// 上記の(3)の処理を区別して書くと次のような処理になる.
// FileOutputStream fout = new FileOutputStream(file);
// BufferedOutputStream out = new BufferedOutputStream(fout);
out.write(message.getBytes());
out.close();
}
writeWithWriter
とwriteWithOutputStream
の違いは,メソッド内で利用している型のみで,構造がほぼ同じであることに注意してください.
writeWithOutputStream
では,ファイルを開き,その型(ここではFileOutputStream
)を別の型(BufferedOutputStream
)でラップしています.
そして,BufferedOutputStream
で message.getBytes()
の返り値をwrite
メソッドで書き出しています.
message.getBytes()
は名前から想像できるように,文字列(String
型)のバイト配列を返します.
このことから,OutputStream
は文字データ(Character
型)ではなく,バイナリデータ(Byte
型)を扱うことに注意しましょう.
加えて,利用している型は異なりますが,名前が似ている型があることにも注意しましょう.
例えば,writeWithWriter
メソッドでは,中で FileWriter
を利用していますが,
writeWithOutputStream
メソッドでは,FileWriter
ではなく,FileOutputStream
を利用しています.
OutputStream型色々
OutputStream
型もWriter
型と同様に多くの型が存在します.
ファイルに書き出すときは,FileOutputStream
を使いますが,典型的には
OutputStream
の機能のみ(write
メソッドにInetger
型を渡す)を使うことが多いでしょう.
FileOutputStream
- ファイル(
File
型)にデータを書き込むためのOutputStream
型.
- ファイル(
ByteArrayOutputStream
- メモリ上にデータを書き出し,バイト配列で取得できる
OutputStream
型.
- メモリ上にデータを書き出し,バイト配列で取得できる
GZIPOutputStream
- この
OutputStream
にデータを書き出すと zip 圧縮されるようになる.
- この
InputStream型
InputStream
はデータを読み込むための Stream であり,バイナリデータを読み込みます.
使い方は Reader
とほぼ同じで,Stream を開き,そこからデータを読み取ります.
read
メソッドで1バイトのデータを読み込みます.この時,Integer
型でデータが返されます.
返り値となるデータが-1の場合,これ以上,読み取るデータがないことを表します.
InputStream型色々
InputStream
型もReader
型と同様に多くの型が存在します.
ファイルからデータを読み出すときは,FileInputStream
を使います.
また,読み込むときにバッファリングしたい場合は,BufferedInputStream
を使うことが多いでしょう.
それでも,本講義で扱うプログラムでは,引数のないread
メソッドを呼び出し,1バイト単位で読み込む方法で十分でしょう.
FileInputStream
- ファイル(
File
型)からバイナリデータを読み込むためのInputStream
型.
- ファイル(
BufferedInputStream
- データをバッファリングして読み込むための
InputStream
型.
- データをバッファリングして読み込むための
ByteArrayInputStream
- バイト配列から1バイトずつデータを読み込むための
InputStream
型.
- バイト配列から1バイトずつデータを読み込むための
GZIPInputStream
- gzip圧縮されたファイルを
FileInputStream
で開き,このGZIPInputStream
でラップして読み込むと,gzip圧縮された内容を読み込むことが可能です.
- gzip圧縮されたファイルを
例題4 InputStreamを利用したCat
InputStream
はバイナリデータですので,行の概念がありません.改行コードも文字も同列に扱われるためです.
それでも,例題1のようなプログラムを作成可能です.
1バイトずつ読みこみ,1バイトずつ書き出せば良いのです.
以下の例をコンパイル,実行してください.
import java.io.*;
public class CatByStream{
void cat(String file) throws IOException{
System.out.printf("========== %s ==========%n", file);
FileInputStream in = new FileInputStream(file);
this.printFileContent(in);
in.close();
}
void printFileContent(FileInputStream in) throws IOException{
Integer data;
while((data = in.read()) != -1){
System.out.write(data);
}
}
// run や main メソッドは省略.
}
このプログラムのprintFileContent
メソッドを見てみましょう.
FileInputStream
型の変数in
に対してread
メソッドを呼び出し,1バイトのデータを受け取っています.
読み取れるデータがない場合は -1
が帰ります.
そして,受け取ったデータを変数data
に代入し,System.out.write
メソッドが標準出力に書き出しています.
このように1バイト単位で読み出し,書き出しすることでも,Catコマンドを実現可能です.
例題5 単純なファイルコピー2
それでは,例題3 単純なファイルコピーを InputStream
/OutputStream
を使って書き直して見ましょう.
クラス名は SimpleCopier2
としてください.
例題6 pnm 画像の生成
pnm 画像とは,pbm, pgm, ppmの総称で非常に単純な画像フォーマットです. それぞれ,portable binary map, portable gray map, portable pix mapの略です. ここで,ppm 画像を作成します. 3バイトで1画像を表します. 画素とは画像の1ピクセルのことです.
ppm画像は,次のようなフォーマットです.各行は1バイトの改行(\n
)で区切られます.
このうち,WIDTH
は横幅を表す整数値,HEIGHT
は高さを表す整数値で,画像データはバイナリデータで画素の左上から始まり左に向かって出力されます.
一番右端のデータが書かれれば,一段下の行の左端からのデータが書き出されます.
そして,1画素あたり,R(赤成分),G(緑成分),B(青成分)の順で書き出され,これがWIDTH*HEIGHT*3
バイト続きます.
P6
WIDTH HEIGHT
255
画像データ
このようなppm画像で,下に示すようなグラデーション表示をしてみましょう. 256×256 の大きさで,左上が黒(RGBがそれぞれ0),左下が赤,右上が青,右下がマゼンタ(RGBでRとB成分が255,G成分が0)になるように画像を作成してみましょう. なお,ppm 画像は,macOSのプレビューで確認できます.
では,GradiationGenerator
というクラス名で作成してみましょう.
生成した画像を gradiation.ppm
というファイルに出力しましょう.
// import文は省略
public class GradiationGenerator {
void run() throws IOException{
OutputStream out = // gradiation.ppm に出力する OutputStream を構築する.
this.writeHeader(out);
this.writeBody(out);
out.close();
}
void writeBody(OutputStream out) throws IOException{
// 各画素をR, G, B それぞれ1バイトで出力する.
}
void writeHeader(OutputStream out) throws IOException{
out.write('P'); // ヘッダ部分は文字で表される.
out.write('6');
out.write('\n'); // 環境が変わっても \n を出力する必要がある.
out.write('2'); // 横幅
out.write('5');
out.write('6');
out.write(' ');
out.write('2'); // 高さ
out.write('5');
out.write('6');
out.write('\n');
out.write('2'); // 1画素の1色成分の最大値
out.write('5');
out.write('5');
out.write('\n');
}
// mainメソッドは省略.
}