ファイルを扱う型
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("../lesson01/BigAndSmall.java");
上記のように,カレントディレクトリを元に,パスの指定も可能です.
指定したファイルが存在しない場合でも問題なく実体を作成できます.
ファイルが存在しているかは,lsコマンドに必要なFile型のメソッド
にも載せているように File
型変数に対して,exists
メソッドを呼び出すことで確認できます.
例題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 .. # ディレクトリを指定した場合,中身を表示する.
lesson01/ lesson02/ lesson03/ lesson04/
lesson05/ lesson06/ lesson07/
$ java ListFiles ../lesson01
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 ../lesson00 # 存在しない場合
ls: ../lesson00: No such file or directory
表示の順序,改行の位置は必ずしも同じでなくても構いません.
lsコマンドに必要なFile型のメソッド
では,ls
コマンドを作成していきましょう.ls
コマンドを
作成するために,File
型の次の3つ(4つ)メソッドが利用できます.File
型の
変数 file
に対してメソッドを呼び出すと思ってください.
- ファイル,ディレクトリの名前を取得する.
file.getName()
- ファイル,もしくはディレクトリ名が
String
型として返る.
- ファイル,もしくはディレクトリ名が
- ファイルとディレクトリを区別する.
file.isDirectory()
- ディレクトリならば,
Boolean
型のtrue
が返る. - ディレクトリでないなら(ファイルであれば),
Boolean
型のfalse
が返る.
- ディレクトリならば,
file.isFile()
- 一般ファイルならば,
Boolean
型のtrue
が返る. - 一般ファイルでないなら(ディレクトリであれば),
Boolean
型のfalse
が返る. isDirectory
の判定と,isFile
の判定のどちらかを利用すれば良いでしょう.
- 一般ファイルならば,
- ファイルとディレクトリの存在を確認する.
file.exists()
- ファイル,もしくはディレクトリが存在すれば,
Boolean
型のtrue
が返る.存在しなければfalse
が返る.
- ファイル,もしくはディレクトリが存在すれば,
- ディレクトリ内のファイル,ディレクトリの一覧を取得する.
file.listFiles()
File
型の配列(File[]
)が返る.file.isDirectory()
がtrue
を返さない場合,listFiles
メソッドはnull
を返します.
lsコマンドの作成
さて,lsコマンドに必要なFile型のメソッドにある
4つのメソッドを利用して,ls
コマンドを作成しましょう.
次のコードを元に作成してください.以下のコードの....
の部分に適切な命令を書きましょう.
// import文を書く.
....
public class ListFiles{
void run(String[] args){
for(String arg: args){
File thisFile = // ....
// argを元に,File型の変数を作成する.
this.listFile(thisFile);
}
if(args.length == 0){
File currentDirectory = // ...
// カレントディレクトリ(".")を表す File 型の実体を作成する.
this.listFile(currentDirectory);
}
}
void listFile(File target){
if(this.isExist(target)){
if(....){ // 引数に与えられた target がディレクトリの場合
this.listFilesInDirectory(target);
}
else{
System.out.printf("%s%n", ....);
// 引数のファイルの名前を出力する.
}
}
}
void listFilesInDirectory(File dir){
// 引数に受け取ったディレクトリの中身一覧を取得する.
File[] files = ....
// for文で files を繰り返す.
for(....){
// 配列の各要素であるファイルの名前を出力する.
}
}
Boolean isExist(File target){
Boolean exists = // .....
// target が指し示すファイルが存在するかを確認する.
// File型の existsメソッドを利用する.
if(!exists){ // ファイルが存在しない場合
// 指定されたファイル名は存在しない旨を出力する.
System.out.printf("ListFiles: %s: No such file or directory%n",
target.getName());
}
return exists;
}
// mainメソッドは省略
}
例題2. Fileの情報を出力するプログラム.
概要
ファイルの情報を出力するプログラムを作成しましょう. コマンドライン引数で指定されたファイルの次の情報を取得して出力してください.
- ファイルの権限
ls -l
で表示されるrwx
のこと.rwx
はそれぞれ,読み込み権限,書き込み権限,実行権限を表します.権限があれば文字が表示され,権限がなければ-
で表されます.r--
であれば,内容は読めるが,書き込み,実行が不可能であることを表します.
- 絶対パス
- 相対パス(コマンドラインで指定されたパス)
- ファイル名(ディレクトリ名を含まない名前)
- 隠しファイルか否か.
- 最終更新日
- ファイルの長さ.
情報取得のために必要なメソッド.
以下のメソッドで必要な情報が取得できます.これらのメソッドも全て,File
型が持ちます.
以下の説明では,lsコマンドに必要なFile型のメソッド
と同じく,File
型の変数 file
に対してメソッドを呼び出すと思ってください.
- ファイルの権限を取得する.
file.canRead()
: ファイルが存在し,読み込み権限があればBoolean
型のtrue
を返します.file.canWrite()
: ファイルが存在し,書き込み権限があればBoolean
型のtrue
を返します.file.canExecute()
: ファイルが存在し,実行権限があればBoolean
型のtrue
を返します.
- 絶対パス
file.getAbsolutePath()
: この実体が表すファイルの絶対パスをString
型で返します.
- 相対パス
file.getPath()
: この実態が表すファイルのパスをString
型で返します.実体を作成するときに渡した文字列がそのまま返されます.
- ファイル名
file.getName()
: lsコマンドに必要なFile型のメソッドで示した通りです.
- 隠しファイルか否か
file.isHidden()
: ファイルが隠しファイルであれば,Boolean
型のtrue
を返します. macOSであれば,.
から始まるファイルは隠しファイルです.
- 最終更新日
file.lastModified()
: 最終更新日をLong
型で返します. 日付(Date
)型に変換するには,Date date = new Date(file.lastModified())
としてください.
- ファイルの長さ
file.length()
: ファイルの長さをLong
型で返します.
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 May 12 15:43:20 JST 2017 FileInfo.java (/Users/tamada/ksuap/lesson07/FileInfo.java)
$ java FileInfo ListFiles.java ~/.bashrc /usr/bin/java
rw- 1621 Fri May 12 15:32:17 JST 2017 ListFiles.java (/Users/tamada/ksuap/lesson07/ListFiles.java)
rw- 578 Fri May 12 13:27:36 JST 2017 /Users/tamada/.bashrc (/Users/tamada/.bashrc) 隠しファイル
r-x 58560 Wed Sep 14 09:55:30 JST 2017 /usr/bin/java (/usr/bin/java)
例題3. treeコマンド
概要
次に,tree
コマンドのように,ディレクトリのツリー構造を表示しましょう.
クラス名は,TreeViewer
としてください.
ヒント
- ディレクトリの数とファイルの数を数える必要がありますので,フィールドにディレクトリ数,ファイル数を格納する
Integer
型の変数を宣言しましょう. traverse
メソッドを宣言しましょう.File
型の変数とインデントレベルを表す数値(Integer
型)を引数として受け取ってください.- 返り値はありません(
void
です). - インデントレベルに応じた空白を出力し,引数のファイルの名前(パスは含みません)を出力しましょう.
- 引数で受け取った
File
型変数がファイルであった場合,ファイル数をインクリメントしてメソッドを終了してください (return
してください). - 引数で受け取った
File
型変数がディレクトリであった場合,次の処理を行なってください.- ディレクトリ数をインクリメントしてください.
- ディレクトリの中身を取得してください(
listFiles
). - 受け取った
File
型の配列の各要素に対して,traverse
メソッドを呼び出してください.- その際,引数で受け取ったインデントレベルに +1 して呼び出してください.
- 再帰呼び出しを行なっています.
- ループが終了すれば,
traverse
メソッドも終了です.
run
メソッドは次の処理を行なってください.File
型の変数を宣言してください.- コマンドライン引数の0番目の要素を
File
型に変換してください. - 変換した
File
型の実体を先ほど宣言したFile
型変数に代入してください. traverse
メソッドを呼び出してください.- 第1引数は先ほど作成した
File
型の変数,インデントレベルは0としてください.
- 第1引数は先ほど作成した
traverse
メソッドの呼び出し後,ディレクトリ数,ファイル数を出力してください.
実行例
$ java TreeViewer prog
prog/
lesson01
Adder.java
... 途中省略
XPrinter.java
lesson02
DateExample.class
... 途中省略
StringBuilderExample.java
lesson03
ArgsSorter.class
... 途中省略
TrapezoidalRulePi.java
lesson04
ArgsPrinter2.class
... 途中省略
StatsValues.java
lesson05
Complex.java
... 途中省略
SquareRoot.java
lesson06
Bound.class
... 途中省略
ThrowingExercise2.java
lesson07
FileInfo.class
... 途中省略
ListFiles.java
8 directories, 98 files
このようにディレクトリが存在しなくなるまでディレクトリを掘り進んでください. コマンドライン引数で渡す文字列は1つで良いです(複数の引数に対応する必要はありません).