コンテンツにスキップ

入出力まとめ

Linux における代表的な入出力

Javaの前にLinuxにおける入出力を知っておいたほうがいいと思います。
Javaプログラムを実行している環境であるLinuxでは、代表的な入出力として以下があります。

  • 標準入出力
  • ファイル入出力

標準入出力は、主に画面に映し出されるもの・キーボードや他のプログラムからの入力などが挙げられます。
幾つかコマンドを実行して入出力を確認してください。

名称 説明
標準出力1 echo "出力内容" 画面に出力
標準出力2 echo "出力内容" >> file.txt 標準出力されたものを>でファイル書込、>>で追記.(リダイレクトという)
標準入力1 read VAL 変数VALに格納。echo $VALで標準出力に表示できる
標準入力2 cat << END_OF_LINE END_OF_LINEという行が出る前入力を続ける。EOFEOLという行が出るまで続けることが多い。
標準入力3 下記参照 echoの標準出力を | (パイプライン) を用いて、trでキャッチしている。trは置換コマンド。-d(delete)なので、Hを除去して、ELLOが出るはず。
ファイル出力 echo "HELLO" >> hello.txt >>を用いてhello.txtに追記。>で追記せずにファイル出力
ファイル入力 cat < hello.txt hello.txtを読み込む.

下記参照されるところ

echo "HELLO" | td -d 'H'

Javaにおける入出力

Javaでは、ストリームと呼ばれる順序付けられたデータの列を扱います。
大別して2種類あります。

名称 説明
バイトストリーム 8bit単位でバイナリデータ(画像やプログラムデータなど文字で表現されないデータ)を扱う
文字ストリーム 16bit単位でUTF-16を扱う

それらを利用するクラスは以下の通りです。

種類 バイトストリーム 文字ストリーム
入力 InputStream Reader
出力 OutputStream Writer

それらの代表的なメソッドを以下に示します。

名前 処理
InputStream.read() 1byteを読み込み、INT型で0-255(8bit10進数)の何れか値を返す。
Reader.read() 1文字を読み込み、INT型で0-65535(16bit10進数)で返す。
OutputStream.write(int i) 1byte(変数iの下位8bit)を書込
Writer.write(int i) 1文字(変数iの下位16bit)を書き込む。

これらをファイルやバッファ用に継承したもののうち代表的なものが以下のものです。

InputStream/OutputStream

名称 説明
ByteArrayInputStream バイト型の配列を入力する。
BufferedInputStream 8192Byte(=8KiB)をバッファ(一時的で高速な保存領域)に溜め込み、入力する。
FileInputStream ファイルから1Byte毎に読み込む。
PipedInputStream 並列処理(スレッド処理)で別の処理からの出力を入力する

Outputの場合は、適宜InputStreamをOutputStreamに返れば大体同じです。

Outputの場合はこのほかに、PrintStreamというクラスもあります。

PrintStreamはテキスト出力します。System.out.println()PrintStreamを利用しています。

////////////////////////////////////////////////
// File入力する
///////////
// 文字列連結用
StringBuilder sb = new StringBuilder();
// FileInputStream sample.txtを読込
FileInputStream fis = new FileInputStream("sample.txt");
while(true){
    int line = fis.read(); // 1byteずつ読込、その1byteを返す。
    if(line == -1) break;  // lineが-1を取ったらファイル入力終了
    else sb.append(line);  // sbに追記する
}
System.out.println(sb.toString()); //標準出力に吐く
/////////////////////////////////////////////////////////
// Bufferedを併用してみる
////////////////
sb.setLength(0); //StringBuilderの中身を空にする。
// Bufferedを併用
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("sample.txt") );
while(true){
    int line = bis.read(); // 8KiB毎にバッファ読込しておき、1byteずつ返す
    if(line == -1) break;
    else sb.append(line);
}
//////////////////////////////////////////////////////////
// 入力したファイルを別のファイルに出力する
///////////////////
BufferedOutputStream bos = null;
// エラーが発生しても`bos.close()`を実行しないといけないので`try-catch-finally`を利用する。
try {
    // sample.copy.txtに出力する
    bos = new BufferedOutputStream(new FileOutputStream("sample.copy.txt"));
    // ただのコピーだとつまらないので1行目にメッセージ入れる。

    String mesg = "***** THIS FILE IS COPIED FILE!!! USING JAVA PROGRAM *****";
    byte[] mesg_bytes =mesg.getBytes();
    bos.write(mesg_bytes);
    // 入力した文字列を追記する
    bos.write(sb.toString().getBytes());
    // Flush(書き込み)する。(Flush(フラッシュ)-> 書込み でピンとくるようにしておく。)
    bos.flush();
}catch(Exception e){
    e.printStackTrace(); // Exceptionは printStackTrace() を利用するとエラーの詳細をprintしてくれる。
}finally{
    try{
        //エラーを吐こうが、吐かないが、バッファのクローズを最後に行う。バッファが開きっぱなしは良くない、というか危ない。
        bos.close();
    }catch(IOException e){
        e.printStackTrace();
    }
}

上記例でもわかる通り、write()byte[]しか受け付けてくれません。
ここでDataOutputStreamを利用すれば、writeUTF()やwriteCharなどが利用でき他の型でもOutputできます。

Reader/Writer

文字ストリームにも色々あります。

  • CharArrayReader
  • BufferedReader/Writer
  • FileReader/Writer
  • PrintWriter
  • StringWriter
  • PipedReader/Writer
  • InputStreamReader
  • OutputStreamWriter

fWriter = null;
BufferedReader bufReader = null;
BufferedWriter bufWriter = nill;

try{
    // インスタンス生成
    fWriter = new FileWriter("HelloWorld.sh");
    bufReader = new BufferedReader(new FileReader("sample.txt"));
    bufWriter = new BufferedWriter(new FileWriter("copied.txt"));
    // FileWriteのみならバッファつかわないのでflush()しない
    fWriter.write("#!/bin/bash");
    fWriter.write("echo HelloWorld!");
    // lineがnullになるまでLoop.
    while((String line = bufReader.readLine()) != null){
        bufWriter.write(line);
    }
    // 書込
    bufWriter.flush();
}finally{
    try{
        //ストリームを閉じる
        bufWriter.close();
        bufReader.close();
    }catch(IOException e){
        System.err.println(e);
    }
}

そのほか

前述したDataOutputStream(もちろんDataInputStreamも)をはじめとして、様々な入出力方法があります。

あとは単なるコピーならば、Javaのバージョン8で追加されたNew I/O 2のもの(Filesクラスなど)を利用するほうが楽です。

参考: ファイルについて

また、読み書きの際に文字コードを指定したり変換したりすることもできます。

参考: bituse.info

文字コード変換に関しては、クラスによっては講義で実施するような課題ですので、試してみても良いと思います。(文字コードを検出する、UTF-8からEUC-JPに変更するなど)


最終更新日: 2021年4月30日