Javaでディレクトリ配下のファイル属性を一覧で出力できるプログラム


仕事であるディレクトリ配下にあるファイルなどの情報を一覧で出力する業務が発生したので
それ用にプログラムを組んでみました。


<ul>
<title><b>プログラム要件</b></title>
<li>『ファイルパス　ファイル名　サイズ　最終更新日時』　の順で出力する</li>
<li>ファイルパスの先頭にトップディレクトリは含めいない（./xxxxx/xxxxx.txtという形式）</li>
<li>ファイル情報は拡張子を含める</li>
<li>サイズはbyte単位で出力</li>
<li>最終更新日時のフォーマットは『yyyy-mm-dd HH:MM:SS』とする</li>
<li>各情報をスペースで区切る</li>
<li>対象がファイルでなくディレクトリの場合はサイズではなくディレクトリの中のファイル数を出力する（ディレクトリの中のファイル数を再起的に探索）</li>
<li>総ファイル数　総ディレクトリ数　総ファイル数を出力する</li>
</ul>

```java
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileTime;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Date;
import java.util.Locale;
import java.util.Scanner;
import java.util.stream.Stream;

public class Main {
    //
    private static int count = 0;
    private static int fileCount = 0;
    private static int dirCount = 0;
    private static int totalSize = 0;

    public static void main(String[] args) throws java.io.IOException{

        //コマンドラインで出力対象のトップディレクトリまでの、実行ファイルからの相対パスを記入
        System.out.println("トップディレクトリ名を入力してください");
        @SuppressWarnings("resource")
        Scanner sc1 = new Scanner(System.in);
        String line1 = sc1.nextLine();

        Path topDirName = Paths.get(line1);

        //トップトップディレクトリ以下の全てのファイル及びディレクトリのパスのストリームを取得
        try(Stream<Path> stream = Files.walk(topDirName)) {
            //トップディレクトの情報は表示しない（スキップする）
            stream.skip(1).forEach(p -> {


                    try {
                        //ファイル属性を取得
                        BasicFileAttributes attributes = Files.readAttributes(p, BasicFileAttributes.class);

                        //一番最初の階層は.\で固定
                        if(p.getNameCount() <= 2){
                            System.out.print("./");
                            //2階層以降
                        }else{
                            //トップディレクトリ名を削除し、パスから最下層のファイル名を除く
                            StringBuilder sb = new StringBuilder();
                            sb.append(p.getParent() + " ");
                            sb.delete(0,sb.toString().indexOf((int)'/'));
                            ////ファイルパスを出力
                            System.out.print("." + sb.toString());
                        }
                        //ファイル名を出力
                        System.out.print(p.getFileName() + " ");

                        //対象がディレクトリの場合
                        if (Files.isDirectory(p)){
                            //ディレクトリ数をインクリメント
                            dirCount++;
                            File dir = new File(p.toString());
                            //カウンタをリセット
                            count = 0;
                            count = count(dir.listFiles());
                            //ディレクトリ内のファイル及び、フォルダを出力
                            System.out.print("Dir("+ count + ")" + " ");
                            //対象がディレクトリ出ない場合
                        }else{
                            //ファイルサイズを出力
                            System.out.print(attributes.size()+ " ");
                            //ファイル数をインクリメント
                            fileCount++;
                            //ファイル容量を加算
                            totalSize += attributes.size();

                        }
                        //ファイルの最終更日時を出力
                        Date firstDate = new Date();
                        FileTime time = FileTime.fromMillis( firstDate.getTime() );
                        LocalDateTime ldt =  LocalDateTime.ofInstant( time.toInstant(), ZoneId.systemDefault());
                        System.out.println(ldt.format( DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)
                                .withLocale( Locale.JAPANESE ) ) );


                    } catch (IOException e) {
                        // TODO 自動生成された catch ブロック
                        e.printStackTrace();
                    }
            });

            System.out.println("ファイルの数" + " : " + fileCount);
            System.out.println("ディレクトリの数" + " : " + dirCount);
            System.out.println("総容量" + " : " + totalSize);

        }catch(IOException e) {
            System.out.println(e);
        }
    }

    //ディレクトリの中身のそうファイル数をカウントする（サブディレクトリも再起的にカウント）
    private static int count(File[] list) {
        for (File f : list) {
            if (f.isDirectory()) {
                count(f.listFiles());
            } else if (f.isFile()) {
                count++;
            }
        }
        return count;
    }
}
```

実行結果
※Windowsの場合はディレクトリのプロパティに記述されている総サイズ、総ファイル数、総ディレクトリ数と一致します
Macの場合だと何故かズレが出ます。というよりwindowsの時とMacの時では同じディレクトリでもサイズが違います。
ファイルシステムの影響かもしれませんし、1KB=1000bとしているのかもしれません。
![475b1db852fd8399b72f587cf189e5fb.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2052494/8fc36d0c-c9f9-2b93-c8e6-d495e57515fd.png)