はじめに なぜ「ファイル更新日時取得」が業務で重要なのか
業務システムでは、「前回処理してから更新されたファイルだけを再処理したい」「一定期間更新されていないログを削除したい」「外部システムからのファイルが本当に最新か確認したい」といった場面で、ファイルの更新日時を扱うことがとても多いです。
更新日時を見ずに処理すると、「古いファイルを何度も処理してしまう」「本当は更新されているのに気づかない」といった、じわじわ効いてくる不具合につながります。
C# では、File クラスや FileInfo クラスを使って、ファイルの更新日時を簡単に取得できます。
ここでは、プログラミング初心者向けに、基本の API から、実務で使えるユーティリティ化、「更新されたかどうか」の判定ロジックまで、かみ砕いて解説していきます。
基本の API File.GetLastWriteTime と FileInfo.LastWriteTime
一番シンプルな更新日時取得
まずは、「特定のファイルの更新日時を取得して表示する」という、一番シンプルな例から見てみましょう。
using System;
using System.IO;
class Program
{
static void Main()
{
string path = @"C:\data\report.csv";
DateTime lastWrite = File.GetLastWriteTime(path);
Console.WriteLine($"更新日時: {lastWrite}");
}
}
C#File.GetLastWriteTime は、指定したパスのファイルの「最終更新日時」を DateTime 型で返します。
ここで返ってくるのは「ローカル時刻(PC のタイムゾーンを反映した時刻)」です。
日本の PC であれば、日本時間として解釈できる値になります。
更新日時は、「そのファイルの中身が最後に書き換えられた時刻」を表します。
「いつ作られたか」ではなく、「いつ最後に変更されたか」を知りたいときに使います。
FileInfo を使った書き方
同じことは FileInfo クラスでも書けます。
サイズや作成日時など、他の情報も一緒に扱いたいときは、FileInfo を使うとコードがまとまりやすくなります。
using System;
using System.IO;
class Program
{
static void Main()
{
string path = @"C:\data\report.csv";
FileInfo info = new FileInfo(path);
DateTime lastWrite = info.LastWriteTime;
Console.WriteLine($"更新日時: {lastWrite}");
}
}
C#FileInfo.LastWriteTime も、ローカル時刻の DateTime を返します。
「サイズも欲しい」「作成日時も欲しい」といった場合は、FileInfo を使うのが定番です。
ローカル時刻と UTC 時刻 LastWriteTimeUtc の意味
LastWriteTime と LastWriteTimeUtc の違い
FileInfo には、LastWriteTime のほかに LastWriteTimeUtc というプロパティもあります。
名前の通り、こちらは「UTC(協定世界時)」での最終更新日時を返します。
using System;
using System.IO;
class Program
{
static void Main()
{
string path = @"C:\data\report.csv";
FileInfo info = new FileInfo(path);
DateTime localTime = info.LastWriteTime;
DateTime utcTime = info.LastWriteTimeUtc;
Console.WriteLine($"ローカル時刻: {localTime}");
Console.WriteLine($"UTC 時刻 : {utcTime}");
}
}
C#日本時間は UTC より 9 時間進んでいるので、例えばローカルが「2025-01-23 18:00」であれば、UTC は「2025-01-23 09:00」のようになります。
国内だけで完結するシステムならローカル時刻だけでも困らないことが多いですが、ログの統一や他システムとの連携を考えると、「内部では UTC で持つ」という設計もよく使われます。
業務でのざっくりした使い分け
初心者向けの指針としては、次のように考えると分かりやすいです。
画面表示やログ出力など、「人間が直接見るもの」はローカル時刻(LastWriteTime)で扱う。
システム間連携や DB 保存など、「後でタイムゾーンを変換する可能性があるもの」は UTC(LastWriteTimeUtc)で扱う。
たとえば、「DB には UTC で保存し、画面に出すときだけ日本時間に変換する」といったパターンです。
最初から完璧を目指さなくてよいですが、「ローカルと UTC の二種類がある」ということだけ知っておくと、後で困りにくくなります。
実務で使えるユーティリティ 単体ファイルの更新日時取得
存在チェック込みのユーティリティメソッド
毎回 File.Exists と File.GetLastWriteTime を書くのは面倒なので、「存在チェック込みの更新日時取得」ユーティリティを用意しておくと便利です。
using System;
using System.IO;
public static class FileLastWriteTimeUtil
{
public static DateTime GetLastWriteTime(string filePath)
{
if (!File.Exists(filePath))
{
throw new FileNotFoundException($"ファイルが見つかりません: {filePath}", filePath);
}
return File.GetLastWriteTime(filePath);
}
public static DateTime GetLastWriteTimeUtc(string filePath)
{
if (!File.Exists(filePath))
{
throw new FileNotFoundException($"ファイルが見つかりません: {filePath}", filePath);
}
return File.GetLastWriteTimeUtc(filePath);
}
}
C#使い方の例は次の通りです。
class Program
{
static void Main()
{
string path = @"C:\data\report.csv";
try
{
DateTime lastWrite = FileLastWriteTimeUtil.GetLastWriteTime(path);
Console.WriteLine($"更新日時(ローカル): {lastWrite}");
DateTime lastWriteUtc = FileLastWriteTimeUtil.GetLastWriteTimeUtc(path);
Console.WriteLine($"更新日時(UTC) : {lastWriteUtc}");
}
catch (FileNotFoundException ex)
{
Console.WriteLine("エラー: " + ex.Message);
}
}
}
C#ここでのポイントは、「存在しない場合は既定値ではなく、例外として扱う」設計にしていることです。
業務的に「ファイルがないのは異常」であることが多いので、その場合は例外で止めたほうがバグに気づきやすくなります。
「存在しないなら null」を返すバージョン
一方で、「存在しなければ null として扱いたい」というケースもあります。
その場合は、DateTime?(null 許容)で返すメソッドを用意します。
public static class FileLastWriteTimeUtil
{
public static DateTime? TryGetLastWriteTime(string filePath)
{
if (!File.Exists(filePath))
{
return null;
}
return File.GetLastWriteTime(filePath);
}
}
C#呼び出し側では、null かどうかで存在有無を判定できます。
class Program
{
static void Main()
{
string path = @"C:\data\report.csv";
DateTime? lastWrite = FileLastWriteTimeUtil.TryGetLastWriteTime(path);
if (lastWrite == null)
{
Console.WriteLine("ファイルが存在しません。");
}
else
{
Console.WriteLine($"更新日時: {lastWrite.Value}");
}
}
}
C#「例外で止めるか」「null で返すか」をメソッドごとに分けておくと、呼び出し側の意図が明確になります。
更新日時を使った業務ロジックの例
「前回処理以降に更新されたファイルだけ処理する」
業務で非常によくあるのが、「前回バッチ実行以降に更新されたファイルだけを対象にしたい」という要件です。
たとえば、「前回実行時刻を DB に保存しておき、それ以降に更新されたファイルだけ取り込む」といったケースです。
using System;
using System.IO;
public static class FileUpdateFilterUtil
{
public static string[] GetUpdatedFiles(
string directoryPath,
DateTime lastProcessedTime,
string searchPattern = "*.*")
{
if (!Directory.Exists(directoryPath))
{
throw new DirectoryNotFoundException($"ディレクトリが見つかりません: {directoryPath}");
}
string[] files = Directory.GetFiles(directoryPath, searchPattern);
var updatedList = new System.Collections.Generic.List<string>();
foreach (string file in files)
{
DateTime lastWrite = File.GetLastWriteTime(file);
if (lastWrite > lastProcessedTime)
{
updatedList.Add(file);
}
}
return updatedList.ToArray();
}
}
C#使い方の例は次の通りです。
class Program
{
static void Main()
{
string dir = @"C:\import";
DateTime lastProcessed = new DateTime(2025, 1, 20, 0, 0, 0);
string[] updatedFiles = FileUpdateFilterUtil.GetUpdatedFiles(
dir,
lastProcessed,
"*.csv"
);
Console.WriteLine("前回処理以降に更新されたファイル:");
foreach (string file in updatedFiles)
{
Console.WriteLine(file);
}
}
}
C#ここでの重要ポイントは、「更新日時を基準にして『前回より新しいかどうか』を判定している」ことです。
これにより、「毎回全ファイルを処理する」のではなく、「差分だけ処理する」バッチを簡単に作れます。
一定期間更新されていないファイルを削除する
もう一つよくあるのが、「30 日以上更新されていないログファイルを削除する」といった、期限付きのクリーンアップ処理です。
この場合も、更新日時を使って判定できます。
using System;
using System.IO;
public static class OldFileCleanupUtil
{
public static int DeleteNotUpdatedFiles(string directoryPath, int days)
{
if (!Directory.Exists(directoryPath))
{
throw new DirectoryNotFoundException($"ディレクトリが見つかりません: {directoryPath}");
}
DateTime threshold = DateTime.Now.AddDays(-days);
int deletedCount = 0;
foreach (string filePath in Directory.GetFiles(directoryPath))
{
DateTime lastWrite = File.GetLastWriteTime(filePath);
if (lastWrite < threshold)
{
File.Delete(filePath);
deletedCount++;
}
}
return deletedCount;
}
}
C#使い方の例は次の通りです。
class Program
{
static void Main()
{
string dir = @"C:\logs\app";
int deleted = OldFileCleanupUtil.DeleteNotUpdatedFiles(dir, days: 30);
Console.WriteLine($"削除したファイル数: {deleted}");
}
}
C#ここでのポイントは、「基準日時(threshold)を先に計算しておき、それより古いかどうかで判定している」ことです。DateTime.Now.AddDays(-30) のように、「今から 30 日前」を求める書き方は、作成日時のときと同様、更新日時でも頻出します。
作成日時との違いと使い分け
「いつ作られたか」と「いつ最後に変わったか」
ファイルには、作成日時(CreationTime)と更新日時(LastWriteTime)の両方があります。
ざっくり言うと、次のように使い分けます。
いつ作られたファイルかを知りたいときは、作成日時。
いつ最後に中身が変わったかを知りたいときは、更新日時。
たとえば、「古いログを削除したい」場合、どちらを使うかは運用ルール次第です。
「作られてから 30 日経ったら消す」のか、「最後に更新されてから 30 日経ったら消す」のかで、使うプロパティが変わります。
実務では更新日時を基準にすることが多い
実務では、「最近使われていないファイルを消したい」「前回処理以降に変更されたファイルだけ処理したい」といった要件が多く、その場合は更新日時を基準にすることが多いです。
一方、「いつ受信したファイルかを知りたい」といった場合は、作成日時を使うこともあります。
大事なのは、「自分がやりたいことに対して、どちらの意味が合っているか」を意識して選ぶことです。
「なんとなく CreationTime を使う」「なんとなく LastWriteTime を使う」ではなく、「何を基準にしたいのか」を先に言葉にしてみると、迷いにくくなります。
例外とエラー処理を意識した更新日時取得
どんな例外が起こり得るか
ファイル更新日時の取得では、次のような理由で例外が発生する可能性があります。
ファイルが存在しない、権限がなくてアクセスできない、パスが不正または長すぎる、ファイルシステムに問題がある、などです。
呼び出し側での例外処理の例を見てみます。
using System;
using System.IO;
class Program
{
static void Main()
{
string path = @"C:\data\report.csv";
try
{
DateTime lastWrite = FileLastWriteTimeUtil.GetLastWriteTime(path);
Console.WriteLine($"更新日時: {lastWrite}");
}
catch (FileNotFoundException ex)
{
Console.WriteLine("ファイルが見つかりません: " + ex.Message);
}
catch (UnauthorizedAccessException ex)
{
Console.WriteLine("権限エラーが発生しました: " + ex.Message);
}
catch (IOException ex)
{
Console.WriteLine("入出力エラーが発生しました: " + ex.Message);
}
catch (Exception ex)
{
Console.WriteLine("想定外のエラーが発生しました: " + ex.Message);
}
}
}
C#実務では、これらのメッセージをログに残しておくことで、「どのファイルの更新日時取得に、どんな理由で失敗したか」を後から追跡できます。
まとめ 実務で使えるファイル更新日時取得ユーティリティの考え方
ファイル更新日時の取得は、「差分処理」「古いファイルの整理」「最新データの判定」など、業務システムの効率と安定性を支える重要な要素です。
だからこそ、「ただ LastWriteTime を読む」だけで終わらせず、ユーティリティとして整理しておく価値があります。
File.GetLastWriteTime や FileInfo.LastWriteTime を使って、更新日時を DateTime として正しく扱うこと。
存在チェック込みのユーティリティ(例外を投げる版と、null を返す版)を用意し、用途に応じて使い分けること。
ローカル時刻と UTC(LastWriteTimeUtc)の違いを理解し、「人が見る用」と「システム内部用」で使い分けること。
更新日時を使って「前回処理以降に更新されたファイルだけを対象にする」「一定期間更新されていないファイルを削除する」といった業務ロジックを組み立てること。
作成日時との違いを意識し、「自分が知りたいのは『いつ作られたか』なのか『いつ最後に変わったか』なのか」を言葉にしてから、どちらを使うか決めること。
ここまで押さえておけば、「どのファイルが最新なのか分からない」「古いファイルが溜まり続けてディスクが圧迫される」といった、現場でよくある悩みをかなり減らせます。
