2016-11-10 第7回目 ファイル入出力(1/2)

本日のテーマ

ファイルを扱う型

File型

Javaでファイルを扱うときは File 型を利用します. 名前はFile型ですが,ファイルもディレクトリも同じ型として扱います.

なお,File型を利用するときは,java.io.File のインポートが必要です.File型の 実体を作成するにはファイル名,もしくはディレクトリ名を文字列(String型)で渡しましょう.

File dir1  = new File(".");
File dir2  = new File("../path/to/some/dir");
File file1 = new File("ファイル名");
File file2 = new File("../autumn01/BigAndSmall.java");

上記のように,カレントディレクトリを元に,パスの指定も可能です.

例題1. lsコマンドの作成

ここでは,lsコマンドに相当するプログラムを作成しましょう.lsコマンドは コマンドライン引数に渡された情報によって次のように挙動が変わります.

lsコマンドの出力例

$ java ListFiles
Complex.java            Factorial2.java         Fibonacci4.java         SquareRoot.java
ComplexCalculator.java  Fibonacci2.java         GrandTotal2.java
CubicRoot.java          Fibonacci3.java         Matrix.java
$ ls Complex.java
Complex.java
$ java ListFiles ..
autumn01/ autumn02/ autumn03/ autumn04/ autumn05/ autumn06/ autumn07/
$ java ListFiles ../autumn01
Adder.java             EvenPrinter.java       LeapYear.java          OddPrinter2.java
BackSlashPrinter.java  EvenPrinter2.java      Multiplication.java    PositiveChecker.java
BigAndSmall.java       GrandTotal.java        OddPrinter.java        XPrinter.java
$ java ListFiles ../autumn00
ls: ../autumn00: No such file or directory

lsコマンドに必要なFile型のメソッド

では,lsコマンドを作成していきましょう.lsコマンドを 作成するために,File型の次の3つ(4つ)メソッドが利用できます.File型の 変数 file に対してメソッドを呼び出すと思ってください.

lsコマンドの作成

さて,lsコマンドに必要なFile型のメソッドにある 4つのメソッドを利用して,lsコマンドを作成しましょう. 次のコードを元に作成してください.以下のコードの....の部分に適切な命令を書きましょう.

// import文を書く.
....
public class ListFiles{
    void run(String[] args){
        for(String arg: args){
            File thisFile = .... // argを元に,File型の変数を作成する.
            this.listFile(thisFile);
        }
    }
    void listFile(File target){
        if(this.isExist(target)){
            if(....){ // 引数のファイルがディレクトリの場合
                this.listFilesInDirectory(target);
            }
            else{
                System.out.printf("%s%n", ....); // 引数のファイルの名前を出力する.
            }
        }
    }
    void listFilesInDirectory(File dir){
        // 引数に受け取ったディレクトリが持つファイル,ディレクトリの一覧を取得する.
        File[] files = .... 
        // for文で files を繰り返す.
        for(....){
            // 配列の各要素であるファイルの名前を出力する.
        }
    }
    Boolean isExist(File target){
        if(....){ // ファイルが存在しない場合
            // 指定されたファイル名は存在しない旨を出力する.
            System.out.printf("ListFiles: %s: No such file or directory%n", ....); 
        }
        return .... // ファイルが存在するかを返す(if文の条件の反転).
    }
    // mainメソッドは省略
}

例題2. Fileの情報を出力するプログラム.

概要

ファイルの情報を出力するプログラムを作成しましょう. コマンドライン引数で指定されたファイルの次の情報を取得して出力してください.

情報取得のために必要なメソッド.

以下のメソッドで必要な情報が取得できます.これらのメソッドも全て,File型が持ちます. 以下の説明では,lsコマンドに必要なFile型のメソッドと同じく,File型の変数 file に対してメソッドを呼び出すと思ってください.

Fileの情報を出力するプログラムの作成.

// import文を書く.
....
public class FileInfo{
    void run(String[] args){
        for(String arg: args){
            File thisFile = .... // argを元に,File型の変数を作成する.
            this.showFileInfo(thisFile);
        }
    }
    void showFileInfo(File target){
        if(....){ // ファイルが存在する場合.
            this.showInfo(target);
        }
        else{
            // 指定されたファイル名は存在しない旨を出力する.
            System.out.printf("FileInfo: %s: No such file or directory%n", ....); 
        }
    }
    void showInfo(File target){
        System.out.printf(
            "%s %6d %s %s (%s) %s%n", 
            getMode(target), 
            ...., // ファイルの長さを指定する.
            ...., // ファイルの最終更新日を Date 型で指定する.
            ...., // ファイルの相対パスを指定する.
            ...., // ファイルの絶対パスを指定する.
            getHidden(target)
        );
    }
    String getHidden(File file){
        if(....){
            return "隠しファイル";
        }
        return "";
    }
    String getMode(File file){
        String rwx = "";
        // 読み込み権限があるか確認する.
        if(....) rwx = rwx + "r";
        else     rwx = rwx + "-";
        
        // 書き込み権限があるか確認する.
        if(....) rwx = rwx + "w";
        else     rwx = rwx + "-";

        // 実行権限があるか確認する.
        if(....) rwx = rwx + "x";
        else     rwx = rwx + "-";

        return rwx;
    }
    public static void main(String[] args){
        FileInfo info = new FileInfo();
        info.run(args);
    }
}

実行例

$ java FileInfo FileInfo.java
rw-   1617 Fri Oct 21 15:43:20 JST 2016 FileInfo.java (/Users/tamada/ksucseap/autumn07/FileInfo.java) 
$ java FileInfo ListFiles.java ~/.bashrc /usr/bin/java
rw-   1621 Fri Oct 21 15:32:17 JST 2016 ListFiles.java (/Users/tamada/ksucseap/autumn07/ListFiles.java) 
rwx    578 Fri Oct 21 13:27:36 JST 2016 /Users/tamada/.bashrc (/Users/tamada/.bashrc) 隠しファイル
r-x  58560 Wed Sep 14 09:55:30 JST 2016 /usr/bin/java (/usr/bin/java) 

例題3. treeコマンド

概要 

次に,treeコマンドのように,ディレクトリのツリー構造を表示しましょう. クラス名は,TreeView としてください.

ヒント

実行例

$ java TreeView prog
prog/
    autumn01
        Adder.java
        ... 途中省略
        XPrinter.java
    autumn02
        DateExample.class
        ... 途中省略
        StringBuilderExample.java
    autumn03
        ArgsSorter.class
        ... 途中省略
        TrapezoidalRulePi.java
    autumn04
        ArgsPrinter2.class
        ... 途中省略
        StatsValues.java
    autumn05
        Complex.java
        ... 途中省略
        SquareRoot.java
    autumn06
        Bound.class
        ... 途中省略
        ThrowingExercise2.java
    autumn07
        FileInfo.class
        ... 途中省略
        ListFiles.java

8 directories, 98 files

このようにディレクトリが存在しなくなるまでディレクトリを掘り進んでください. コマンドライン引数で渡す文字列は1つで良いです(複数の引数に対応する必要はありません).

ページのトップに戻る

練習問題

1. ファイルを探すコマンド FileFinder

指定されたディレクトリ以下の特定の名前をもつファイルが存在するかを探索するプログラムを作成してください. 以下のように指定してください.

java FileFinder ファイル名 探索ディレクトリ

例題3が参考になるでしょう.探索には,TreeViewtraverseと同じように 再帰呼び出しを行いましょう. ファイル名の一致を確認するには,値の一致性を確認しましょう

見つかった場合に,全てのパスを出力し,見つからなかったら,その旨を出力するようにしましょう. 見つかったら,とりあえず,結果を入れるListにパス(File型変数)を追加しましょう. そして,最後に Listの大きさを確認し,見つかったか,見つからなかったかを判断しましょう.

実行例

$ java FileFinder TreeView.java prog
prog/autumn07/TreeView.java
$ java FileFinder TreeView.java ../
../prog/autumn07/TreeView.java
../2016spring/prog/07/TreeView.java
$ java FileFinder TreeView.notfound prog
TreeView.notfound: Not found.

2. ディレクトリを作成するコマンド mkdir

ディレクトリを作成するコマンド MakeDirectory を作成しましょう. 作成したいディレクトリのパスを持つFile型変数を作成し,その変数に対して,mkdir メソッドを呼び出すとディレクトリを作成できます.

実行例

$ java ListFiles ..
autumn01 autumn02 autumn03 autumn04 autumn05 autumn06 autumn07
$ java MakeDirectory ../autumn00
$ java ListFiles ..
autumn00 autumn01 autumn02 autumn03 autumn04 autumn05 autumn06 autumn07
$ java ListFiles ../autumn00
$ java MakeDirectory ../autumn00/not/exist/parent/dir
../autumn00/not/exist/parent/dir: could not make directory.

3. ディレクトリを作成するコマンド mkdir の改良

先ほどの MakeDirectory は途中のディレクトリが存在しないとき, ディレクトリの作成に失敗しました.そのような場合でもディレクトリが作成できるようにしましょう.

ディレクトリを作成するコマンド mkdirでは,mkdirメソッドを利用しました. ここでは,mkdirメソッドの代わりに,mkdirsメソッドを利用してください. これで,途中のディレクトリが存在しない場合でも作成してくれます.

クラス名を MakeDirectories としてください. なお,コマンドライン引数で複数の値を受け取れるようにしてください.

実行例

$ java MakeDirectories a/b/c/d/e/f
$ java ListFiles a
b

4. ファイル,ディレクトリを削除するコマンド remove

ファイル,ディレクトリを削除するコマンド Remover を作成してください. コマンドライン引数で受け取った複数のパスのファイルを削除するコマンドです. ディレクトリ内にファイルがあったとしても,それらも全て削除してください.

ただし,必要なファイルを削除しないように気をつけてください.

削除は,File型の変数に対して,deleteメソッドを呼び出してください. ただし,ディレクトリ内が空でなければ,deleteメソッドは失敗します. ディレクトリが空でない場合は,そのディレクトリ内部のファイル,ディレクトリを削除してから削除するようにしましょう. 再帰呼び出しを用いると実現できるでしょう.

実行例

$ java ListFiles a/b/c/d/e
f
$ java Remover a/b/c/d/e/f
$ java ListFiles a/b/c/d/e
$ java Remover a
$ java ListFiles a
ls: a: No such file or directory.

ページのトップに戻る

まとめ