ファイル名生成は「衝突させずに意味を持たせる」ための技
業務システムでは、ログファイル、レポート出力、アップロードファイルの保存先など、「新しいファイル名を決める」場面が山ほどあります。
ここで適当に "output.txt" みたいな名前を使い回すと、上書き事故が起きたり、どのジョブが出したファイルか分からなくなったりします。
だからこそ、「ファイル名生成」をユーティリティとして整理しておくと、
「衝突しない」「意味が読み取れる」「OS に優しい」ファイル名を、毎回同じルールで作れるようになります。
基本方針:「いつ・誰の・何の」ファイルかを名前に埋め込む
最低限入れたい情報を決める
実務でのファイル名は、だいたい次のような要素で構成すると分かりやすくなります。
- 何のファイルか(prefix)
- いつ作られたか(タイムスタンプ)
- 誰/何の処理が作ったか(ID や種別)
- 拡張子
これをコードで表現すると、例えばこんなイメージです。
report-20250127-101530-job123.csv
upload-20250127-101530-8f3a2c1e.png
「何となくそれっぽい名前」ではなく、「どの情報を入れるか」を先に決めてから、ユーティリティで組み立てるのがポイントです。
実務で使えるシンプルなファイル名生成ユーティリティ
日時+連番で「その日中は衝突しない」名前を作る
まずは、日付・時刻と連番を組み合わせた、シンプルなユーティリティを作ってみます。
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.atomic.AtomicInteger;
public final class FileNameGenerator {
private FileNameGenerator() {}
private static final DateTimeFormatter DATE_TIME =
DateTimeFormatter.ofPattern("yyyyMMdd-HHmmss");
private static final AtomicInteger SEQ = new AtomicInteger(0);
public static String generate(String prefix, String extension) {
String timestamp = LocalDateTime.now().format(DATE_TIME);
int seq = SEQ.updateAndGet(i -> (i >= 9999) ? 0 : i + 1);
StringBuilder sb = new StringBuilder();
if (prefix != null && !prefix.isBlank()) {
sb.append(prefix).append("-");
}
sb.append(timestamp)
.append("-")
.append(String.format("%04d", seq));
if (extension != null && !extension.isBlank()) {
sb.append(".").append(extension);
}
return sb.toString();
}
}
Java使い方はこうです。
String name1 = FileNameGenerator.generate("report", "csv");
String name2 = FileNameGenerator.generate("report", "csv");
System.out.println(name1); // 例: report-20250127-110305-0001.csv
System.out.println(name2); // 例: report-20250127-110305-0002.csv
Javaここで深掘りしたい重要ポイントは、「“時間+連番”で衝突確率を下げている」ことです。
同じ秒の間に複数回呼ばれても、連番が増えるのでファイル名がかぶりません。
また、日付・時刻を入れておくことで、「いつ出力されたファイルか」が名前から一目で分かります。
例題:レポート出力ファイル名を一元管理する
呼び出し側から「命名ルール」を追い出す
レポート出力ジョブを考えてみます。
ユーティリティがないと、ついこんなコードを書きがちです。
// よくない例
String fileName = "report-" + System.currentTimeMillis() + ".csv";
Javaこれを、先ほどのユーティリティに置き換えます。
import java.nio.file.Files;
import java.nio.file.Path;
public class ReportJob {
private final Path outputDir;
public ReportJob(Path outputDir) {
this.outputDir = outputDir;
}
public Path run() throws Exception {
String fileName = FileNameGenerator.generate("report", "csv");
Path output = outputDir.resolve(fileName);
Files.writeString(output, "id,name\n1,foo\n2,bar\n");
return output;
}
}
Javaここでのポイントは、「“ファイル名の作り方”を ReportJob から追い出している」ことです。
ReportJob は「レポートを出力する」ことだけに集中し、
「どういうルールでファイル名を付けるか」は FileNameGenerator に任せています。
こうしておくと、「タイムスタンプのフォーマットを変えたい」「連番をやめて UUID にしたい」といった変更も、
ユーティリティ側だけを直せばよくなり、業務ロジックを触らずに済みます。
UUID を使った「ほぼ絶対にかぶらない」ファイル名
衝突リスクを極限まで下げたいとき
「とにかくかぶらなければよい」「人間が見て意味を読む必要はない」という場面では、UUID を使うのも有効です。
import java.util.UUID;
public final class UuidFileNames {
private UuidFileNames() {}
public static String random(String prefix, String extension) {
String uuid = UUID.randomUUID().toString().replace("-", "");
StringBuilder sb = new StringBuilder();
if (prefix != null && !prefix.isBlank()) {
sb.append(prefix).append("-");
}
sb.append(uuid);
if (extension != null && !extension.isBlank()) {
sb.append(".").append(extension);
}
return sb.toString();
}
}
Java使い方はこうです。
String name = UuidFileNames.random("upload", "png");
// 例: upload-3f9a1c2b4d6e7f8090a1b2c3d4e5f607.png
Javaここでの重要ポイントは、「“人間にとっての意味”より“衝突しないこと”を優先している」ことです。
アップロードファイルの保存名など、「ユーザーには見せない内部的な名前」には、このスタイルが向いています。
一方で、運用者が直接ファイルを見て調査するような場面では、日時や種別を含めたほうが親切です。
OS に優しいファイル名にするための注意点
使わないほうがいい文字を避ける
Windows などでは、ファイル名に使えない文字がいくつかあります。
/ \ : * ? " < > | など
また、スペースや全角記号を多用すると、コマンドラインやスクリプトから扱いづらくなります。
ユーティリティ側で、「危ない文字を安全な文字に置き換える」処理を入れておくと安心です。
public final class FileNameSanitizer {
private FileNameSanitizer() {}
public static String sanitize(String raw) {
if (raw == null || raw.isBlank()) {
return "";
}
String s = raw.trim();
s = s.replaceAll("[\\\\/:*?\"<>|]", "_");
return s;
}
}
Javaこれをファイル名生成の前処理として使います。
String safePrefix = FileNameSanitizer.sanitize(userInputPrefix);
String name = FileNameGenerator.generate(safePrefix, "txt");
Javaここで深掘りしたいのは、「“ユーザー入力をそのままファイル名に使わない”という習慣」です。
ユーザーが自由に入力できる文字列は、必ずサニタイズしてからファイル名に組み込むようにすると、
OS 依存のトラブルや、意図しないパス解釈のリスクを減らせます。
まとめ:ファイル名生成ユーティリティで身につけたい感覚
ファイル名生成は、「とりあえず適当な文字列をくっつける」ではなく、
「衝突させずに、後から見ても意味が分かる名前を、毎回同じルールで作る」ための技です。
押さえておきたい感覚はこうです。
ファイル名には「何のファイルか」「いつ作られたか」「必要なら ID」を埋め込む。
時間+連番、または UUID を使って、同時実行でもかぶりにくい名前にする。
命名ルールはユーティリティに閉じ込め、業務ロジックからは追い出す。
ユーザー入力は必ずサニタイズしてからファイル名に組み込む。
