Windows環境でのファイル移動完了を確実に検知する方法

  • URLをコピーしました!

業務自動化やファイル連携のスクリプトを組んでいると、「ファイルが存在しているのに処理が失敗する」という経験をしたことはありませんか?

特にNASや共有フォルダとのやり取りでは、見た目にはファイルが届いているのに、実は書き込み中だった…なんてことも珍しくありません。私自身、初心者の頃はmoveコマンドで十分だと思い込んでいたのですが、現場ではうまくいかず苦労しました。

この記事では、そうしたトラブルの原因と、確実に「ファイル移動完了」を見極めるための実践的な方法を紹介します。

この記事を読むとわかること

  • PowerShellでファイルロックやサイズ変動をチェックする方法
  • robocopyによる再試行やログ出力の活用法
  • 安定しない方法の実例と、避けるべき理由
目次

ファイル移動が完了したと見なせず困った場面

外部システムとのデータ連携や業務自動化の一環として、ファイル移動後に処理を行うスクリプトを書くことはよくあります。

ただ、ファイル転送の完了を待たずに次の処理が走ってしまうと、未完成のファイルを読み込んでしまい、エラーやデータ欠損につながるケースが出てきます。

特に共有フォルダやNASとのやりとりがあると、物理的にはファイルが「存在」していても、完全に書き込みが終わっていないことがあるのが厄介です。

自分も慣れないうちは単純なmoveでうまくいくと思い込んでいたのですが、後続処理がコケて原因がわからず困った経験があります。

ネットワーク越しの転送で起きやすい落とし穴

ネットワークドライブやNASなど、リモート環境へのファイル転送では「ファイルが見える=完了」ではない点が重要です。

Windowsエクスプローラー上で見えるようになったとしても、実際にはキャッシュや非同期転送の関係で、完全に書き込みが終わっていないことがあるからです。

こういった状況でバッチ処理やスケジューラが動くと、ファイルを読み込んだ時点で中身が不完全だったり、読み込みエラーになることがあります。結果的に、「ファイルはあったのに処理できていなかった」という現象が発生します。

この手のトラブルは、見た目には再現が難しく、ログにも明確なエラーが残らないことが多いため、気づくのが遅れることが多いです。私も過去に何度か問い合わせを受けて、ようやく根本原因に気づいたことがありました。

ファイルが未完成のまま後続処理が動いてしまう

バッチファイルやPowerShellスクリプトで定期的にフォルダを監視している場合、目的のファイル名が見つかった瞬間に処理を進めるロジックにしていることが多いです。

ただ、この方法だと「ファイルの存在」だけを条件にしているため、肝心の中身が書き終わる前に処理してしまうリスクがあります。

これは、ファイルを「書いている途中」の状態ではロックがかかっていたり、サイズが変動していたりするため、本来はその変化をきちんと見て判断する必要があります。気づいたときには既に後続処理が走っていて、手動リカバリが必要…なんてこともあるでしょう。

業務上の信頼性を考えると、この「完了したかどうかの見極め」がかなり重要になります。

Windowsでファイル移動完了を検知する選択肢

ファイル移動に関して「moveコマンドで完結」と考えていた時期もありましたが、実際には「移動後のファイルが読み込み可能で、安定している」状態でないと意味がないです。

そこで、Windows環境でよく使われる手法をいくつか比較してみます。

単純なmoveでは防げない理由

Windowsのmoveコマンドは、あくまでシェルレベルでのファイル操作です。

処理としては速いのですが、ネットワーク越しの転送や大容量ファイルでは、完了を待たずに次の処理に進んでしまう危険性があります。

また、move自体はエラー検出も限定的で、ログも残りません。そのため、処理の成否が不明瞭なまま進行してしまうこともあり、実際に自分が組んでいたバッチでも、moveの直後にtypeで中身を読んだら途中までしか読めていなかった…ということがありました。

ファイルの確実な移動・転送が求められる業務では、moveだけに頼るのは危険だと感じています。

ファイルロックのチェックという考え方

一つのアプローチとして、「ファイルがロックされているかどうか」を見る方法があります。

つまり、まだ書き込み中なら排他ロックがかかっているはずなので、それが外れるのを待つ、というものです。

この方法ではPowerShellやVBScriptなどからTry-Catchを使って、ファイルを開けるかどうかを試す実装になります。ロックが外れた=書き込み完了と判断できるため、後続処理のタイミングをずらすことが可能になります。

ただし、すべてのアプリケーションが適切にロックをかけるとは限らないため、絶対的な指標ではありません。

robocopyの再試行とログ機能の活用

より堅実な方法として、robocopyの活用があります。robocopyはWindows標準の高機能コピーコマンドで、リトライ回数・インターバル・ログ出力などが細かく制御できます。

robocopy \\src\share \\dst\share *.csv /MOV /R:5 /W:10 /LOG:C:\logs\robocopy.log

この例では、.csvファイルを5回まで再試行しつつ移動し、ログも記録します。転送に失敗した場合も明示的にログに残るため、後から確認しやすくなります。

業務用途ではこのようにログと再試行設定を組み合わせるだけでも、かなーり安心感が違います。

PowerShellで移動完了を確実に検知する方法

PowerShellを使えば、より柔軟かつ細やかな検知処理が実装できます。

ここでは、ロック解放の待機、サイズの安定確認、簡易な読み取りテストなど、3つの実装パターンを紹介します。

1. Try-Catchとループでロック解放を待つ実装

ファイルが「開ける」状態=ロックが解放された、と見なす簡易的な検知方法です。以下はその例です。

$path = "C:\shared\data.csv"
while ($true) {
    try {
        $stream = [System.IO.File]::Open($path, 'Open', 'Read', 'None')
        $stream.Close()
        break
    } catch {
        # ファイルがロック中などで開けなかった場合、2秒待って再試行
        Start-Sleep -Seconds 2
    }
}

シンプルですが、これで「誰かが書き込んでいる最中」の状態を検知できます。タイミングのズレによる事故を防ぐには効果的です。

ファイルサイズとタイムスタンプの安定を確認する方法

一定時間ごとにファイルサイズと最終更新時刻を比較し、変動がなければ「安定した」と判断する方法もあります。

$path = "C:\shared\data.csv"
$prevSize = -1
do {
    # 現在のファイルサイズを取得
    $currSize = (Get-Item $path).Length

    # 2秒間スリープ(時間差を設けて再チェック)
    Start-Sleep -Seconds 2

    # 2秒後のファイルサイズを再取得
    $newSize = (Get-Item $path).Length

# ファイルサイズが変わっている間はループを継続
# つまり、まだファイルが書き込み中であると判断
} while ($currSize -ne $newSize)

この方法は書き込みが完了しているかをかなり正確に把握できます。大容量ファイルなど、時間がかかる場合でも安全性は高めです。

Get-Contentで読み取り確認する簡易チェック

ファイルが「開けるかどうか」だけでよければ、Get-Contentでの確認も可能です。

try {
    Get-Content "C:\shared\data.csv" -ErrorAction Stop | Out-Null
    Write-Output "ファイル読み取り成功"
} catch {
    Write-Output "読み取り失敗。まだ使用中の可能性あり。"
}

この方法はあくまで簡易チェックですが、他の手法と組み合わせることで「ある程度の安心感」は得られます。

現場で実際に試してやめた方法

理屈の上では正しそうでも、実際の業務では不安定だったり管理しにくかった方法もあります。

ここでは、過去に私が試して「これはやめておこう・・」と判断したものを紹介します。

ファイル一覧を定期監視するバッチ処理の落とし穴

一番初歩的な方法として、特定フォルダのファイル一覧をdirコマンドなどで定期的に監視する処理を書いたことがあります。

ただ、この方法だと「存在しているかどうか」しか見ていないので、内容の完成度やロック状態まではわかりません。

また、タイミングが合わないと、ファイルが生成中なのに処理が走ってしまうことがありました。運用中に1ファイルだけ中途半端に処理されていたことがあって、この方法には限界があると実感しました。

一定時間sleepする手法では不安定だった理由

「5分待てばファイルは届いてるだろう」という発想でsleepを入れた処理も書きました。

でも、これって結局「経験則に頼ってるだけ」なんですよね・・。

ファイルサイズやネットワーク状況によって転送時間は変わるため、同じ処理でもたまたま間に合っていたというだけの話です。不定期に処理が失敗するので、結局sleepだけでは信頼できないと判断しました。

まとめ

単なるmovecopyで完了を見なすのは、業務では危険が伴います。

ロックの検出・サイズの安定・ログ出力など、複数の観点を組み合わせて「本当に完了したかどうか」を判断する仕組みが必要です。

自分の現場では最終的に、robocopyの再試行+PowerShellによる安定確認の組み合わせが最も安定しました。単体ではなく、組み合わせで担保するのが一番現実的だと感じています。

この記事を書いた人

業務システムとWebアプリの開発に20年以上携わるフリーランスエンジニア。
製造業や物流業界のシステム保守・改修を中心に、要件定義から運用改善まで幅広く対応してきました。Laravelや業務改善、AI活用など、現場で実際に試し・使い続けている技術や設計の工夫を、トラブル対応の視点も交えてブログに記録しています。

日々の業務で直面した「困ったこと」をベースに、再現性のあるノウハウをシンプルな言葉で伝えることを意識しています。

目次