リスト5のCプログラムも、ファイル・ポインターを使ってコピーを行います。 ただし、先のリスト3では、コピーが一バイトごとに行われているのに対して、ここ では、コピーは、ファイルの一行毎に行われています。ですから、このプログラム は、「行」という概念のあるテキスト・ファイルのコピーしか、おそらく、うまく 動かないでしょう。
#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 ... といったデータ・タイプに応じたデータの値の取り込みが 可能になる沢山のメソッドを備えています。
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 のインスタンスであることが分かります。
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"); } }