リスト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");
}
}