next up previous contents
Next: 演習課題 Up: File I/O Previous: readwrite

DataInputStream と PrintStream

リスト5のCプログラムも、ファイル・ポインターを使ってコピーを行います。 ただし、先のリスト3では、コピーが一バイトごとに行われているのに対して、ここ では、コピーは、ファイルの一行毎に行われています。ですから、このプログラム は、「行」という概念のあるテキスト・ファイルのコピーしか、おそらく、うまく 動かないでしょう。

リスト 5

#include <stdio.h>
#define BUFSIZE 80

  main (int argc, char ** argv){
       FILE * in , * out ;
       char line[80] ;

       if ( argc != 3 ){
           fprintf(stderr,"Usage: %s file1 file2\n",argv[0]);
           exit(-1);
       }

       if ( ( in = fopen(argv[1],"r")) == NULL ){
           fprintf(stderr,"Can't open file: %s\n",argv[1]);
           exit(-1);
       }

       if ( ( out = fopen(argv[2],"w")) == NULL ){
           fprintf(stderr,"Can't open file: %s\n",argv[2]);
           exit(-1);
       }

       while( (fgets(line,BUFSIZE,in)) != NULL ){
           fprintf(out,"%s",line);
       }
  }

このリスト5に対応するJava プログラムがリスト6です。

ここで、初めて、今までの例とは異なるストリームの作り方をしていることに、注意 してください。一度、生成されたFileInputStream のインスタンス fin は、 コンストラクタ DataInputStream の引数に与えられ、新しい入力ストリーム in が生成されています。ここでの入力ストリームは、今までの2例のような、 FileInputStream ではなく、新しい DataInputStream クラスに属しています。

ここの所は、次のように、一行でまとめて書くことも出来ます。

 DataInputStream din = new DataInputStream(new FileInputStream(argv[0]));

いずれにしても、FileInputStream のクラスの中には、行単位の入力を行う機能が なく、DataInputStreamクラスの中で初めて、行単位の入力を行うメソッド readLine() が定義されることになります。

DataInputStream クラスは、行単位の入力を可能にするだけでなく、ストリームから Int, Long, Float, char ... といったデータ・タイプに応じたデータの値の取り込みが 可能になる沢山のメソッドを備えています。

リスト 6

import java.io.*;

class Copy3 {
  public static void main (String argv[]){
     try {
       FileInputStream fin = new FileInputStream(argv[0]);
       DataInputStream in = new DataInputStream(fin);
       FileOutputStream fout = new FileOutputStream(argv[1]);
       PrintStream out = new PrintStream(new BufferedOutputStream(fout));
       String line ;

       while( (line = in.readLine()) != null ){
          out.println(line);   
       }
       to.flush(); out.println(line);   

     } catch (Exception e ){
          System.err.println("Exception :" + e);   
     }
  }
}

出力の方は、もう少し入り組んでいます。生成されたFileOutputStream の インスタンス fout は、コンストラクタ BufferedOutputStream の引数に与えられ、 その結果が、再び、コンストラクタ PrintStream の引数に与えられ、インスタンス out を生成しています。

この出力ストリームを使って、行を出力しているメソッドは println() です。 このメソッドは、System.out.println(...) の形で、これまで繰り返し登場してき ていました。

次のリスト7は、System クラスのソースの一部です。これを見れば、System.out が、 PrintStream のインスタンスであることが分かります。

リスト 7

public final
class System {

    /**
     * Standard input stream.  This stream is used for reading in character
     * data.
     */
    public static InputStream in;

    /**
     * Standard output stream. This stream is used for printing messages.
     */
    public static PrintStream out;

    /**
     * Standard error stream. This stream can be used to print error messages.
     * Many applications read in data from an InputStream and output messages via
     * the PrintStream out statement.  Often applications rely on command line
     * redirection to specify source and destination files.  A problem with redirecting
%     * standard output is the incapability of writing messages to the screen if the
     * output has been redirected to a file.  This problem can be overcome by sending
     * some output to PrintStream out and other output to PrintStream err.  The
     * difference between PrintStream err and PrintStream out is that PrintStream
     * err is often used for displaying error messages but may be used for any purpose.
     */
    public static PrintStream err;

    static {
	try {
	    in  = new BufferedInputStream(
                      new FileInputStream(FileDescriptor.in), 128);
	    out = new PrintStream(new BufferedOutputStream(
                      new FileOutputStream(FileDescriptor.out), 128), true);
	    err = new PrintStream(new BufferedOutputStream(
                      new FileOutputStream(FileDescriptor.err), 128), true);
	} catch (Exception e) {
	    throw new Error("can't initialize stdio");
	}
    }



maruyama@wakhok.ac.jp