Javaで入出力を扱うには,ストリームという概念の理解が必要です. ストリームとは,データを流れとして扱う仕組みです. データがデータソース(Data Source; データの源,入力元)から流れてくる入力ストリームと, データをデータの出力先(Data Destination; 出力先)に流し込む出力ストリームの2つがあります.
下の画像が入力ストリームを表しています. データソースはファイルやネットワークから,もしくは,別のプログラムであるなど, 入力ストリームを扱う側は知らなくても良いようになっています. とにかく,ストリームを扱う側は,必要なデータが流れてくることさえ理解していれば良いわけです. このような性質のため,Javaでは,あらゆる入出力にストリームを利用します.
入力元がファイルであろうと,ネットワークの先であろうと,受け取る方法は同じです. 入力元がどこであろうと,同じように扱うために,ラッピング という作業が必要になります.
下の画像が出力ストリームを表しています.出力も入力ストリームと同じく, ラッピングを利用して,出力先を気にすることなくデータを書き込めます.
ファイル,ネットワーク,また,メモリに書き込むときにもストリームを利用します.
先ほど,ファイルやネットワーク,さては,メモリの入出力までストリームを利用できると述べました. 異なるものを同じように扱うために,ラッピング(wrapping)と言う概念を利用します. ラッピングは,アダプタパターン(Adapter Pattern)と言われる場合もあります.
ラッピングとは,包むや包装するという意味です.
その意味のとおり,ラッピングを行うには,とある実体を別の型で覆います.
右図のように,別の型で覆うことで,内側の型(Inner
)を外側の型(Outer
)として扱えるようになります.
// Inner.java
public class Inner{
void method1(){
// some operation...
}
}
// Outer.java
public class Outer{
Inner inner
void method2(){
inner.method1();
}
}
// Main.java
public class Main{
void run(){
Inner inner = new Inner();
Outer outer = this.wrap(inner);
outer.method2();
}
Outer wrap(Inner inner){
Outer outer = new Outer();
outer.inner = inner;
return outer;
}
}
Javaのストリームを扱う型は下の図のように,Reader
,Writer
,InputStream
,OutputStream
の4種類に大別できます.
上図を縦のグループで見ると,Reader
/Writer
がテキストデータを
扱う型,InputStream
/OutputStream
がバイナリデータを扱う型です.
バイナリデータとは,画像ファイルや音声ファイルなどです.
文字を扱う型では,HTMLやプログラムのソースファイルなど,テキストデータを扱います.
一方,上図を横のグループで見ると,Reader
とInputStream
が入力ストリームを
表しており,Writer
とOutputStream
が出力ストリームを表しています.
そして,Reader
と呼ばれる型にも複数の型が存在します.Writer
も同じく, 複数のWriter
型が存在します.
この回では,テキストデータを扱う型(Reader
/Writer
)のみを扱います.
ただし,バイナリデータを扱う型であっても使い方はReader
/Writer
とほぼ同じです.
4種類のストリームを扱う場合は,import文が必要です.
それぞれの型の先頭にjava.io.
をつけたものを import してください.
例えば,Reader
と Writer
を使いたい場合は,次の2行がプログラムの先頭に必要です.
import java.io.Reader;
import java.io.Writer;
Reader
型の例えば,FileReader
,BufferedReader
を利用するときには,次の2行が必要です.
import java.io.BufferedReader;
import java.io.FileReader;
複数の import
文をまとめるために,import java.io.*;
としても構いません.
先ほどのReader
とWriter
のimportの2行を1行で書けるようになります.