ファイル操作と入出力

<概要>ファイル操作について学びます。クラスライブラリのマニュアルの読み方についても少しだけ補足します。

例題18-1 指定したファイルの内容を標準出力に表示する。

○プログラム

import java.io.*;

public class ShowFile1{
  public static void main(String[] args){
    if(args.length!=1){
      System.out.println("使用法:java ShowFile1 ファイル");
      System.out.println("例:java ShowFile1 ShowFile1.java");
      System.exit(0);
    }
    String filename=args[0];
    try{
      BufferedReader reader=new BufferedReader(new FileReader(filename));
      String line;
      while((line=reader.readLine())!=null){
        System.out.println(line);
      }
      reader.close();
    }catch(FileNotFoundException e){
      System.out.println(filename+"が見つかりません。");
    }catch(IOException e){
      System.out.println(e);
    }
  }
}


○実行例

D:\atsushi\Java\List18-1>java ShowFile1 test.txt
test.txtが見つかりません。

D:\atsushi\Java\List18-1>java ShowFile1 ShowFile1.java
import java.io.*;

public class ShowFile1{
  public static void main(String[] args){
    if(args.length!=1){
      System.out.println("使用法:java ShowFile1 ファイル");
      System.out.println("例:java ShowFile1 ShowFile1.java");
      System.exit(0);
    }

……省略……

D:\atsushi\Java\List18-1>

○解説

例題13-6で同じようなことをやったからだいたい分かりますね。

java.lang.Object
 |
 +--java.io.Reader
  |
  +--java.io.InputStreamReader
   |
   +--java.io.FileReader

public class FileReader extends InputStreamReader
 public FileReader(String fileName) throws FileNotFoundException

FileReader は、文字ファイルからの読み込みのための簡易クラスです。
FileReader (のインスタンス)をそのまま使ってもいいのですが、
通常はこれを元に BufferedReader というクラス(のインスタンス)を作成します。

java.lang.Object
 |
 +--java.io.Reader
  |
  +--java.io.BufferedReader

public class BufferedReader extends Reader
 public BufferedReader(Reader in)
 public String readLine() throws IOException
 public void close() throws IOException


BufferedReader は、文字、配列、行をバッファリングすることによって、
文字型入力ストリームからテキストを効率良く読み込むためのクラスです。
バッファの大きさを変えるには BufferedReader(Reader in,int sz) コンストラクタを使います。
バッファは大きい方が効率は良いのですが、メモリを多く必要とします。

public BufferedReader(Reader in,int sz)  //BufferedReader クラス ← java.io パッケージ
 指定されたサイズのバッファでバッファリングされた、文字型入力ストリームを作成します。
パラメータ: in - Reader , sz - 入力バッファのサイズ
例外: IllegalArgumentException - sz が 0 以下の場合

ところで、この BufferedReader(Reader in,int sz) コンストラクタは、
例外 IllegalArgumentException を投げるのに、throws 節が書かれていないのは何故でしょうか?
それは、IllegalArgumentException が実行時例外( RuntimeException )のサブクラスだからです。
実行時例外は、たくさんあり、またいろんなところで起きうるので、
いちいちコンパイラもチェックしないのでしたね。
他にもチェックされない例外に、Error (と、そのサブクラス)がありました。

さて、new FileReader(filename) を評価した時点で、ファイルはオープンされ、
ファイルを読むための準備が整ったことになります。

ファイルの読み込みが終了したら、close メソッドを呼んで「ファイルをクローズする」必要があります。
 → reader.close();
これで、読み込みのために確保されていた資源
(メモリやファイルハンドル、ファイルディスクリプタなど)が解放されます。

クラスライブラリのマニュアルを読む

ここまで読み進んでこられた皆さんなら、もうマニュアル(ヘルプ)の殆どを読めるはずです。

java.lang.Object
 |
 +--java.io.Reader
  |
  +--java.io.InputStreamReader
   |
   +--java.io.FileReader


これは FileReader のクラス階層です。
個々のクラスは、属しているパッケージが分かるように、java.io.FileReader のように書かれています。
これは、java.io パッケージの中に FileReader が含まれているという意味です。

例題18-2 標準入力の内容をファイルに書き込む。

○プログラム

import java.io.*;

public class WriteFile1{
  public static void main(String[] args){
    if(args.length!=1){
      System.out.println("使用法:java WriteFile1 作成ファイル");
      System.out.println("例:java WriteFile1 output.txt < input.txt");
      System.exit(0);
    }
    String filename=args[0];
    try{
      BufferedReader reader=new BufferedReader(new InputStreamReader(System.in));
      PrintWriter writer=new PrintWriter(new BufferedWriter(new FileWriter(filename)));
      String line;
      while((line=reader.readLine())!=null){
        writer.println(line);
      }
      reader.close();
      writer.close();
    }catch(IOException e){
      System.out.println(e);
    }
  }
}


○実行例

D:\atsushi\Java\List18-2>java WriteFile1 output.txt<WriteFile1.java

D:\atsushi\Java\List18-2>

○ output.txt

import java.io.*;

public class WriteFile1{
  public static void main(String[] args){
    if(args.length!=1){
      System.out.println("使用法:java WriteFile1 作成ファイル");
      System.out.println("例:java WriteFile1 output.txt < input.txt");
      System.exit(0);
    }

……省略……

○解説

13. PrintWriter writer=new PrintWriter(new BufferedWriter(new FileWriter(filename)));

new FileWriter(filename) を評価した時点で、filename で指定された名前のファイルが
大きさ 0 として(つまり空っぽのファイルとして)作成されます。
もしも、同じ名前を持つファイルが既にあった場合は、上書きします。
上書きされたファイルの内容は一瞬にして無くなってしまいますので、注意して下さい。

java.lang.Object
 |
 +--java.io.Writer
  |
  +--java.io.OutputStreamWriter
   |
   +--java.io.FileWriter

public class FileWriter extends OutputStreamWriter
  //java.io パッケージ
 文字ファイルを書き込むための簡易クラスです。

public FileWriter(String fileName) throws IOException  //FileWriter クラス ← java.io パッケージ
 ファイル名を指定して FileWriter オブジェクトを構築します。
パラメータ: fileName - システムに依存するファイル名の文字列
例外: IOException - 指定したファイルが見つからない場合、または他の入出力エラーが発生した場合

FileWriter は、ファイルへの書き込みを行うクラスです。
FileWriter (のインスタンス)をそのまま使ってもいいのですが、
通常はこれを元に BufferedWriter というクラス(のインスタンス)を作成します。
BufferedReader は、書き込みの際にバッファリングを行うクラスです。

java.lang.Object
 |
 +--java.io.Writer
  |
  +--java.io.BufferedWriter

public class BufferedWriter extends Writer
  //java.io パッケージ
 文字をバッファリングすることによって、文字、配列、
 または文字列を効率良く文字型出力ストリームに書き込みます。

public BufferedWriter(Writer out)  //BufferedWriter クラス ← java.io パッケージ
 デフォルトサイズの出力バッファでバッファリングされた、文字型出力ストリームを作成します。

BufferedReader クラスのインスタンスを作成したら、
更にこれを元に PrintWriter というクラス(のインスタンス)を作成しています。
PrintWriter は、便利なメソッドを数多く持つクラスです。

java.lang.Object
 |
 +--java.io.Writer
  |
  +--java.io.PrintWriter


public class PrintWriter extends Writer  //java.io パッケージ
 フォーマットされたオブジェクトの表現をテキスト出力ストリームに出力します。

public PrintWriter(Writer out)  //PrintWriter クラス ← java.io パッケージ
 自動行フラッシュは行わずに、新しい PrintWriter を作成します。
パラメータ: out - 文字出力ストリーム

16. writer.println(line);

public void println(String x)  //PrintWriter クラス ← java.io パッケージ
 String を出力して、行を終了します。
 このメソッドは、print(String) を呼び出してから println() を呼び出すのと同じように動作します。
パラメータ: x - 出力される String 値

19. writer.close();

public void close()  //PrintWriter クラス ← java.io パッケージ
 ストリームを閉じます。
定義: クラス Writer 内の close

BufferWriter では出力がバッファリングされますので、ファイルクローズを忘れると、
書き込んだつもりの文字列が欠けてしまったりすることがあります。
ファイルクローズ忘れには十分注意しましょう。

ところで、println と言えば、これまで何度も使ってきた System.out.println メソッドを思い出します。
System.out の out は、標準出力を元にして作った PrintStream クラスを型とする static フィールドです
(PrintStream はバイト単位の出力を行い、PrintWriter は文字単位の出力を行います)。
ですから、System.out.println の実行結果は、標準出力に出力されるのです。
また writer は、ファイルを元にして作った PrintWriter クラスの変数です。
ですから、writer.println の実行結果はファイルに出力されるのです。
と言っても、PrintWriter と PrintStream にクラス階層上の関係は無いんですけどね。

public final class System extends Object  //java.lang パッケージ

public static final PrintStream out
  //System クラス ← java.lang パッケージ
 「標準」出力ストリームです。
 このストリームはすでに開いていて、出力データの受け取りが可能です。
 通常、このストリームはディスプレイ出力、
 またはホスト環境やユーザによって指定されるその他の出力先と一致しています。

public class PrintStream extends FilterOutputStream  //java.io パッケージ
 ほかの出力ストリームに機能を追加します。
 具体的には、さまざまなデータ値の表現を簡易的に出力する機能を追加します。

public void println(String x)
  //PrintStream クラス ← java.io パッケージ
 String を出力して、行を終了します。
 このメソッドは、print(String) を呼び出してから println() を呼び出すのと同じように動作します。
パラメータ: x - 出力される String 値

例題18-3 ファイルを削除する。

○プログラム

import java.io.*;

public class DeleteFile1{
  public static void main(String[] args){
    if(args.length!=1){
      System.out.println("使用法:java DeleteFile1 削除ファイル");
      System.out.println("例:java DeleteFile1 trash.txt");
      System.exit(0);
    }
    String filename=args[0];
    File file=new File(filename);
    if(file.delete()){
      System.out.println(filename+"を削除しました。");
    }else{
      System.out.println(filename+"は削除できませんでした。");
    }
  }
}


○実行例

D:\atsushi\Java\List18-3>echo test>trash.txt

D:\atsushi\Java\List18-3>java DeleteFile1 trash.txt
trash.txtを削除しました。

D:\atsushi\Java\List18-3>java DeleteFile1 trash.txt
trash.txtは削除できませんでした。

D:\atsushi\Java\List18-3>

○注意

DOSコマンド echo 本来の処理内容は気にしないとして、
echo test>trash.txt の結果として test という文字列が書き込まれたファイル trash.txt が作成されます。

○解説

11. File file=new File(filename);

File クラスは、ファイルやディレクトリを操作するときに使います。

public class File extends Object implements Serializable, Comparable  //java.io パッケージ
 ファイルおよびディレクトリのパス名の抽象表現です。

public File(String pathname)  //File クラス ← java.io パッケージ
 指定されたパス名文字列を抽象パス名に変換して、新しい File のインスタンスを生成します。
 指定された文字列が空の文字列の場合、結果は空の抽象パス名になります。
パラメータ: pathname - パス名文字列
例外: NullPointerException - pathname 引数が null の場合

12. if(file.delete()){

public boolean delete()  //File クラス ← java.io パッケージ
 この抽象パス名が示すファイルまたはディレクトリを削除します。
 このパス名がディレクトリを示す場合、そのディレクトリが削除されるためには空である必要があります。
戻り値: ファイルまたはディレクトリが正常に削除された場合は true、そうでない場合は false
例外: SecurityException - セキュリティマネージャが存在する場合に、
 セキュリティマネージャの SecurityManager.checkDelete(java.lang.String) メソッドが
 ファイルへの削除アクセスを許可しないとき

例題18-4 ファイルの名前変更。

○プログラム

import java.io.*;

public class RenameFile1{
  public static void main(String[] args){
    if(args.length!=2){
      System.out.println("使用法:java RenameFile1 現在のファイル名 新しいファイル名");
      System.out.println("例:java RenameFile1 oud.txt new.txt");
      System.exit(0);
    }
    String oldfilename=args[0];
    String newfilename=args[1];
    File oldfile=new File(oldfilename);
    File newfile=new File(newfilename);
    if(oldfile.renameTo(newfile)){
      System.out.println(oldfilename+"を"+newfilename+"に変更しました。");
    }else{
      System.out.println(oldfilename+"を"+newfilename+"に変更できませんした。");
    }
  }
}


○実行例

D:\atsushi\Java\List18-4>echo test>oldfile.txt

D:\atsushi\Java\List18-4>java RenameFile1 oldfile.txt newfile.txt
oldfile.txtをnewfile.txtに変更しました。

D:\atsushi\Java\List18-4>echo test>oldfile.txt

D:\atsushi\Java\List18-4>java RenameFile1 oldfile.txt newfile.txt
oldfile.txtをnewfile.txtに変更できませんした。

D:\atsushi\Java\List18-4>

○解説

14. if(oldfile.renameTo(newfile)){

public boolean renameTo(File dest)  //File クラス ← java.io パッケージ
 この抽象パス名が示すファイルの名前を変更します。
パラメータ: dest - 指定されたファイルの新しい抽象パス名
戻り値: 名前の変更が成功した場合は true、そうでない場合は false
例外: SecurityException - セキュリティマネージャが存在する場合に、
 セキュリティマネージャの SecurityManager.checkWrite(java.lang.String) メソッドが
 古いパス名と新しいパス名のどちらかへの書き込みアクセスを許可しないとき
 NullPointerException - パラメータ dest が null の場合

ファイルの名前が変更できない原因は、
・変更元のファイルが見つからなかった
・変更先のファイルが既にあった
の両方が有り得ます。
実行例の場合、二回目の RenameFile1 実行の時には
既に newfile.txt が存在するので、名前変更が出来なくなっています。

例題18-5 ファイルの存在確認。

○プログラム

import java.io.*;

public class RenameFile2{
  public static void main(String[] args){
    if(args.length!=2){
      System.out.println("使用法:java RenameFile2 現在のファイル名 新しいファイル名");
      System.out.println("例:java RenameFile2 oud.txt new.txt");
      System.exit(0);
    }
    String oldfilename=args[0];
    String newfilename=args[1];
    File oldfile=new File(oldfilename);
    File newfile=new File(newfilename);
    if(!oldfile.exists()){
      System.out.println(oldfilename+"が見つかりません。");
    }else if(newfile.exists()){
      System.out.println(newfilename+"はすでに存在します。");
    }else if(oldfile.renameTo(newfile)){
      System.out.println(oldfilename+"を"+newfilename+"に変更しました。");
    }else{
      System.out.println(oldfilename+"を"+newfilename+"に変更できませんした。");
    }
  }
}


○実行例

D:\atsushi\Java\List18-5>java RenameFile2 oldfile.txt newfile.txt
oldfile.txtが見つかりません。

D:\atsushi\Java\List18-5>echo test>oldfile.txt

D:\atsushi\Java\List18-5>echo test>newfile.txt

D:\atsushi\Java\List18-5>java RenameFile2 oldfile.txt newfile.txt
newfile.txtはすでに存在します。

D:\atsushi\Java\List18-5>del newfile.txt

D:\atsushi\Java\List18-5>java RenameFile2 oldfile.txt newfile.txt
oldfile.txtをnewfile.txtに変更しました。

D:\atsushi\Java\List18-5>

○解説

14. if(!oldfile.exists()){

public boolean exists()  //File クラス ← java.io パッケージ
 この抽象パス名が示すファイルが存在するかどうかを判定します。
戻り値: この抽象パス名が示すファイルが存在する場合は true、そうでない場合は false
例外: SecurityException - セキュリティマネージャが存在する場合に、
 セキュリティマネージャの SecurityManager.checkRead(java.lang.String) メソッドが
 ファイルへの読み込みアクセスを許可しないとき


戻る / ホーム