Java Tips | 基本ユーティリティ:ディレクトリ作成

Java Java
スポンサーリンク

ディレクトリ作成は「ログや一時ファイルの置き場を整える」ための技

業務システムでは、ログ出力先、インポートファイル置き場、エクスポート結果の出力先、一時ファイルの作業ディレクトリなど、「ディレクトリが存在していること」が前提の処理がたくさんあります。
ところが、そのディレクトリが事前に作られていなかったり、権限が足りなかったりすると、アプリは平気な顔をして動き出したように見えて、実は裏でエラーを吐き続ける、ということが起きがちです。

だからこそ、「ディレクトリ作成」をユーティリティとしてきちんと設計しておくと、起動時や処理開始時に前提条件を満たせているかを確認しやすくなり、運用トラブルをかなり減らせます。


基本:Files.createDirectory と createDirectories の違いを押さえる

単一ディレクトリを作る createDirectory

Java 7 以降では、java.nio.file.Files を使ってディレクトリを作成します。

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

public class CreateDirBasic {

    public static void main(String[] args) throws IOException {
        Path dir = Path.of("work/output");
        Files.createDirectory(dir);
    }
}
Java

createDirectory は、「親ディレクトリがすでに存在している」前提で、そのディレクトリだけを作ります。
親が存在しない場合や、すでに同名のディレクトリがある場合は例外が投げられます。

階層ごとまとめて作る createDirectories

業務では「work/output/2026/01/23」のように階層が深くなることが多く、親ディレクトリがまだないケースもよくあります。
そのときに便利なのが createDirectories です。

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

public class CreateDirsBasic {

    public static void main(String[] args) throws IOException {
        Path dir = Path.of("work/output/2026/01/23");
        Files.createDirectories(dir);
    }
}
Java

createDirectories は、途中の親ディレクトリも含めて、存在しなければまとめて作ってくれます。
すでに存在しているディレクトリが混ざっていてもエラーにならない、というのが大きな特徴です。

ここで重要なのは、「業務コードでは、ほとんどの場合 createDirectories を使うのが安全」という感覚です。
「親が必ずある」ことを前提にできる場面は意外と少なく、階層ごとまとめて作ってくれるほうが実務では扱いやすいです。


実務で使える「ディレクトリ作成ユーティリティ」の最小形

存在していてもエラーにしない「ensure」系メソッド

「このディレクトリが存在していてほしい。なければ作る。あればそのまま使う」というニーズは非常に多いです。
それを毎回 if 文で書くのではなく、ユーティリティに閉じ込めてしまいましょう。

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

public final class DirUtils {

    private DirUtils() {}

    public static Path ensureDirectory(Path dir) throws IOException {
        Files.createDirectories(dir);
        return dir;
    }
}
Java

使う側はこう書けます。

Path outDir = DirUtils.ensureDirectory(Path.of("work/output"));
System.out.println("出力先ディレクトリ: " + outDir.toAbsolutePath());
Java

createDirectories は、すでに存在している場合でも例外を投げないので、「存在していれば OK、なければ作る」という「ensure」系の用途にぴったりです。

ここで深掘りしたいポイントは、「“存在していることを保証する”という意図をメソッド名に乗せる」ことです。
ensureDirectory と書かれていれば、「この時点でディレクトリが存在する前提を作っているんだな」とすぐに分かります。


「必須ディレクトリ」として扱う場合のユーティリティ

作成に失敗したら起動時に落とす

ログ出力先や一時ディレクトリなど、「ここが作れないならアプリを動かしても意味がない」というディレクトリもあります。
そういう場合は、起動時に作成を試みて、失敗したら即エラーにしてしまうほうが健全です。

import java.io.IOException;
import java.nio.file.Path;

public final class RequiredDirs {

    private RequiredDirs() {}

    public static Path requireDirectory(Path dir, String description) {
        try {
            DirUtils.ensureDirectory(dir);
            return dir;
        } catch (IOException e) {
            throw new IllegalStateException(
                    "必須ディレクトリを作成できませんでした: " + description + " (" + dir + ")", e);
        }
    }
}
Java

起動時にこう呼びます。

Path logDir = RequiredDirs.requireDirectory(Path.of("logs/app"), "アプリケーションログ出力先");
Java

ここでの重要ポイントは、「I/O 例外を業務的な例外(IllegalStateException など)にラップして、“起動条件を満たせなかった”ことを明示する」ことです。
呼び出し側は IOException を意識せず、「このディレクトリが作れなければアプリは起動できない」という意図だけを読めばよくなります。


例題:日付ごとの出力ディレクトリを作るバッチ

日付単位でディレクトリを切る処理

例えば、「毎日実行されるバッチが、その日の結果を output/yyyy/MM/dd に出力する」という処理を考えます。

import java.io.IOException;
import java.nio.file.Path;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

public class DailyExportJob {

    public void run() throws IOException {
        LocalDate today = LocalDate.now();
        Path base = Path.of("output");
        Path dir = buildDateDir(base, today);

        DirUtils.ensureDirectory(dir);

        // ここから先は dir が存在する前提でファイルを書ける
        Path file = dir.resolve("result.csv");
        exportCsv(file);
    }

    private Path buildDateDir(Path base, LocalDate date) {
        String yyyy = DateTimeFormatter.ofPattern("yyyy").format(date);
        String mm   = DateTimeFormatter.ofPattern("MM").format(date);
        String dd   = DateTimeFormatter.ofPattern("dd").format(date);
        return base.resolve(yyyy).resolve(mm).resolve(dd);
    }

    private void exportCsv(Path file) {
        // CSV 出力処理…
    }
}
Java

ここでのポイントは、「ディレクトリの構造を組み立てる責務」と「存在を保証する責務」を分けていることです。
buildDateDir は単にパスを組み立てるだけ、DirUtils.ensureDirectory は存在を保証するだけ、という役割分担にすると、
それぞれのメソッドがシンプルになり、テストもしやすくなります。


ディレクトリ作成で気をつけるべきポイント

「ディレクトリのつもりがファイルだった」ケース

createDirectories は、途中のパスに「通常ファイル」が存在していると例外を投げます。
例えば、work/output がファイルなのに、work/output/2026 を作ろうとすると失敗します。

これは一見レアケースに見えますが、ログファイルとログディレクトリの名前が被っていたり、
人手で誤ってファイルを置いてしまったりすると、実際に起こり得ます。

この場合は、「例外が出たらそのまま落とす」ほうが安全です。
無理に上書きしたり削除したりすると、意図しないデータ消失につながるため、
「ディレクトリが作れない=運用上の問題」として扱うのが実務的です。

権限エラーを「ちゃんと表に出す」

書き込み権限がない場所にディレクトリを作ろうとすると、AccessDeniedException などの I/O 例外が投げられます。
これを握りつぶしてしまうと、「なぜかファイルが出力されない」という分かりにくい状態になります。

RequiredDirs.requireDirectory のように、「どのディレクトリを何の目的で作ろうとして失敗したのか」をメッセージに含めて例外を投げると、
ログを見たときに原因がすぐに分かるようになります。


旧来の File#mkdirs との違いと、今どきの選び方

File#mkdir と mkdirs も一応知っておく

昔からある java.io.File にも、ディレクトリ作成メソッドがあります。

File dir = new File("work/output");
boolean ok = dir.mkdirs(); // 親もまとめて作る
Java

mkdirscreateDirectories と似ていて、「親も含めてまとめて作る」「すでに存在していても true を返す」という挙動です。
ただし、戻り値が boolean で、失敗しても理由が分かりにくい、という弱点があります。

新規コードでは Path + Files を優先する

今から新しく書くコードでは、PathFiles.createDirectories を使うほうがよいです。
理由は、例外で失敗理由が分かること、他のファイル操作 API と一貫性があること、
そして Path ベースのコードのほうがモダンな Java では主流だからです。

既存コードで mkdirs が使われている場合は、急いで書き換える必要はありませんが、
新しくユーティリティを作るなら Path ベースで設計しておくと、後々の拡張がしやすくなります。


まとめ:ディレクトリ作成ユーティリティで身につけるべき感覚

ディレクトリ作成は、「ただフォルダを作る」だけではなく、「アプリが動くための前提条件をコードで保証する」ための行為です。

押さえておきたい感覚はこうです。

単一ディレクトリではなく階層ごと作ることが多いので、基本は Files.createDirectories を使う。
「存在していてほしい」ディレクトリは ensureDirectory のようなユーティリティで、存在保証を一箇所にまとめる。
「作れなければアプリを動かす意味がない」ディレクトリは、起動時に作成を試みて、失敗したら業務的な例外で落とす。
日付ごとの出力先など、「パスの組み立て」と「存在保証」の責務を分けて、コードをシンプルに保つ。
権限エラーやファイルとの衝突は、「運用上の問題」としてきちんと表に出し、ログメッセージで何が起きたかを明確にする。

タイトルとURLをコピーしました