【bat】Windowsのパス長制限(MAX_PATH=260)完全攻略|\\?\プレフィックス・レジストリ設定・robocopy・substまで徹底解説

【bat】Windowsのパス長制限(MAX_PATH=260)完全攻略|\\?\プレフィックス・レジストリ設定・robocopy・substまで徹底解説 bat

バッチファイルで深い階層のフォルダを操作しているとき、突然「ファイル名が長すぎます」や「The filename or extension is too long」というエラーが出て処理が止まることがあります。

これは Windows の伝統的な仕様である MAX_PATH=260文字制限 によるものです。Windows の多くの API が内部で char[MAX_PATH] サイズのバッファを使用しており、これを超えるパスを渡されると失敗します。

本記事では、この制限の仕組みを理解した上で、状況に応じた6つの対処法を実際に動くコードとともに解説します。

スポンサーリンク

MAX_PATH=260 の仕組みを理解する

Windows の歴史的な制限では、パス文字列は 260文字以内(NULL終端文字含む)に収まる必要があります。実際に使えるのは 259文字ですが、ドライブ名と区切り文字を含むため、実質的にはさらに短くなります。

構成要素 文字数
ドライブ名 3文字 C:\
ディレクトリパス 最大235文字程度 folder1\folder2\...
ファイル名 最大255文字(FAT系) filename.ext
合計(NULL含む) 260文字以内

たとえば C:\(3文字)から始まるパスでは、残り 257文字 以内にフォルダ名・区切り文字・ファイル名をすべて収める必要があります。自動生成されたフォルダ名が長い場合や、プロジェクトを深い階層に置いている場合に制限に引っかかります。

エラーが出やすいシナリオ
・npm / pip などのパッケージマネージャが生成する node_modules\... の深い依存関係
・バックアップツールが日付・ホスト名を付けて作成する階層フォルダ
・Maven / Gradle のリポジトリキャッシュ(.m2\repository\...
・日本語フォルダ名(1文字が複数バイトだが、パス長はバイト数でなく文字数でカウント)

6つの対処法の比較

対処法 Windows 10/11 管理者権限 既存スクリプトへの影響 推奨場面
①レジストリでシステム全体の長いパスを有効化 必須(1607以降) 必要 少ない(アプリ対応が必要な場合あり) 開発PC・恒久的な解決
\\?\プレフィックスを付ける 不要 不要 コード修正が必要 一部コマンドへのスポット対応
③robocopy / PowerShell を使う 不要 不要 コマンド変更が必要 コピー・削除・移動
④subst で仮想ドライブを割り当てる 不要 不要 変数変更のみ 既存スクリプトのパスを短縮
⑤mklink でシンボリックリンクを作成 不要 通常必要 なし 固定パスの短縮
⑥ディレクトリ構造を浅く見直す 不要 不要 なし 根本解決

対処法①:Windows 10/11 でシステム全体の長いパスを有効化

Windows 10 Anniversary Update(バージョン1607)以降では、レジストリまたはグループポリシーの設定で システム全体の MAX_PATH 制限を撤廃できます。最も根本的な解決策であり、開発者 PC では最初にこれを行うことをお勧めします。

レジストリで有効化(管理者権限で実行)
@echo off
rem 管理者権限が必要
reg add "HKLM\SYSTEM\CurrentControlSet\Control\FileSystem" ^^
    /v LongPathsEnabled /t REG_DWORD /d 1 /f
echo 長いパスのサポートを有効化しました
echo ※ 設定を反映するには再起動が必要な場合があります
PowerShell で有効化(管理者権限で実行)
# PowerShell でも同様に設定できる
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" `
    -Name "LongPathsEnabled" -Value 1 -Type DWord
Write-Host "長いパスのサポートを有効化しました"

グループポリシーエディタ(gpedit.msc)からも設定できます。「コンピューターの構成」→「管理用テンプレート」→「システム」→「ファイルシステム」→「Win32 の長いパスを有効にする」を「有効」にしてください。

有効化しても動かない場合の注意点
レジストリ設定後も以下の場合は制限が残ります。
・アプリケーション自体が長いパスに未対応(マニフェストに longPathAware の宣言が必要)
・.NET Framework 4.6.1 以前(4.6.2 以降は対応)
・古い cmd.exe 依存のコマンド(cd・dir などの一部動作)
・ネットワーク共有経由のパス

対処法②:\?\ プレフィックスを使う

\\?\ プレフィックスを付けることで、Windows の拡張長パス API(CreateFileW 等の Unicode 版 API)を直接呼び出し、最大約 32,767 文字までのパスを扱えます。レジストリ変更不要で即座に効果があります。

\\?\ プレフィックスの基本的な使い方
@echo off
set "LONG=\\?\C:\very\deep\path\to\a\deeply\nested\folder\filename.txt"

rem ファイルの存在確認
if exist "%LONG%" echo ファイルが存在します

rem コピー
copy "%LONG%" "C:\work\filename.txt"

rem 削除
del "%LONG%"

rem ディレクトリ作成
mkdir "\\?\C:\very\deep\new\folder"
UNCネットワークパスの場合
@echo off
rem 通常のUNCパス: \\server\share\path
rem \\?\ + UNCは \\?\UNC\server\share\path の形式
set "UNC_LONG=\\?\UNC\server\share\very\long\path\file.txt"
copy "%UNC_LONG%" "C:\work\file.txt"
\\?\ を使う際の注意点
・パスには相対パスが使えない(フルパス必須)
.(カレント)や ..(親)などの相対要素も使えない
・すべてのコマンドや API が対応しているわけではない(下の表を参照)
・スラッシュ(/)をバックスラッシュ(\)に変換してから使う
コマンド / API \\?\ 対応 備考
copy 通常動作
del 通常動作
mkdir / md 通常動作
move 通常動作
if exist 通常動作
cd 動作するが %CD% が不正確になる場合あり
dir 基本動作するが /s との組み合わせで問題あり
xcopy × 内部制限により非対応
robocopy ◎(プレフィックス不要) 標準で長いパスに対応
PowerShell -LiteralPath ◎(プレフィックス不要) 標準で長いパスに対応

対処法③:robocopy と PowerShell を使う

robocopy は内部で Unicode API を使用しており、\\?\ プレフィックスなしで長いパスを扱えます。copy / xcopy が失敗する場合の第一選択です。

robocopy でコピー(長いパス対応)
@echo off
rem robocopy は長いパスに標準対応
rem 書式: robocopy "コピー元フォルダ" "コピー先フォルダ" [ファイル名パターン] [オプション]

rem 1ファイルをコピー
robocopy "C:\very\deep\path\to\folder" "C:\work" "filename.txt"

rem フォルダをまるごとコピー(サブフォルダ含む)
robocopy "C:\src\deep\project" "D:\backup\project" /e /copyall

rem 長いパスのフォルダを削除(空フォルダとの同期で削除)
md "C:\empty_temp"
robocopy "C:\empty_temp" "C:\very\deep\path\to\delete" /purge /e
rd "C:\empty_temp"
rd /s /q "C:\very\deep\path\to\delete"
robocopy の終了コードに注意
robocopy は終了コードが 0(変更なし)または 1(コピー成功)のどちらも「成功」です。%ERRORLEVEL%if errorlevel 2 から失敗として扱ってください。robocopy の詳しい使い方はファイルをコピーする方法完全ガイドを参照してください。
PowerShell でコピー・移動・削除
@echo off
rem コピー(-LiteralPath で長いパスを扱う)
powershell -NoProfile -Command ^
    "Copy-Item -LiteralPath 'C:\very\deep\path\file.txt' -Destination 'C:\work\'"

rem フォルダごとコピー
powershell -NoProfile -Command ^
    "Copy-Item -LiteralPath 'C:\very\deep\src' -Destination 'D:\backup\' -Recurse -Force"

rem 削除(-Recurse でフォルダも再帰削除)
powershell -NoProfile -Command ^
    "Remove-Item -LiteralPath 'C:\very\deep\path' -Recurse -Force"

rem 移動
powershell -NoProfile -Command ^
    "Move-Item -LiteralPath 'C:\very\deep\path\file.txt' -Destination 'C:\work\file.txt'"

対処法④:subst コマンドで仮想ドライブを割り当てる

subst コマンドで深い階層のフォルダに短い仮想ドライブレター(例: Z:)を割り当てることで、既存スクリプトをほぼ変更せずにパスを短縮できます。

subst で仮想ドライブを使う
@echo off
rem 長いパスのフォルダを Z: に割り当て
set "LONG_BASE=C:\very\deep\project\src\main\resources"
subst Z: "%LONG_BASE%"

rem Z: を使って操作(短いパスで済む)
copy Z:\config.xml C:\work\
cd /d Z:\
dir

rem 処理が終わったら必ず解除する
subst Z: /d
echo 仮想ドライブを解除しました
バッチ終了時に自動解除する(エラー時も確実に)
@echo off
set "LONG_BASE=C:\very\deep\project\workspace"
set "VDRIVE=Z:"

rem 仮想ドライブを割り当て
subst %VDRIVE% "%LONG_BASE%"
if errorlevel 1 (
    echo エラー: 仮想ドライブの割り当てに失敗しました
    exit /b 1
)

rem 処理本体
call :do_work

rem 処理後に必ず解除(:cleanup へ)
:cleanup
subst %VDRIVE% /d 2>nul
exit /b

:do_work
copy %VDRIVE%\data.txt C:\work\
exit /b
subst の注意点
・割り当ては現在のセッション(ログオン中)のみ有効(再起動で消える)
・他のユーザーや別のプロセスからは同じドライブレターが見えない場合がある
・使い終わったら subst DRIVE: /d で必ず解除する(ゾンビドライブを防ぐ)
・既存のスクリプトのパスを変数で管理していれば変数1か所の変更だけで対応できる

対処法⑤:mklink でシンボリックリンク・ジャンクションを作成する

深い階層のフォルダに対して、浅い場所にシンボリックリンクやジャンクションを作ることでパスを短縮できます。subst と異なり再起動後も残ります。

ジャンクション(管理者権限不要)
@echo off
rem ジャンクション(ディレクトリへのリンク)は管理者権限不要
rem mklink /j リンク先 ターゲット
mklink /j "C:\work\proj" "C:\very\deep\project\workspace\main"

rem C:\work\proj がショートカットとして機能
dir "C:\work\proj"

rem ジャンクションを削除(ターゲットは削除されない)
rd "C:\work\proj"
シンボリックリンク(管理者権限 or 開発者モード必要)
@echo off
rem シンボリックリンク(ファイル用)
rem mklink リンク先 ターゲット
mklink "C:\work\config.ini" "C:\very\deep\path\config.ini"

rem シンボリックリンク(ディレクトリ用)
rem mklink /d リンク先 ターゲット
mklink /d "C:\work\data" "C:\very\deep\project\data"

長いパスのファイルを列挙・確認する方法

dir /s が途中で失敗する場合、PowerShell または robocopy で列挙します。

PowerShell でパス長を確認・一覧表示
@echo off
rem 260文字を超えるファイルを一覧表示
powershell -NoProfile -Command ^
    "Get-ChildItem -LiteralPath 'C:\very\deep' -Recurse -Force ^
    | Where-Object { $_.FullName.Length -gt 260 } ^
    | Select-Object FullName, @{N='Length';E={$_.FullName.Length}} ^
    | Sort-Object Length -Descending ^
    | Format-Table -AutoSize"
robocopy でファイル一覧のみ取得(ドライラン)
@echo off
rem /l オプションで実際にはコピーせず一覧だけ表示
robocopy "C:\very\deep\source" "C:\dummy" /l /e /256
rem /256 オプションで長いパスのサポートを明示的に有効化(Windows 10対応版)

長いパスのファイルを安全に削除する方法

delrd /s が失敗する場合は robocopy の /PURGE を使います。

robocopy /PURGE で長いパスのディレクトリを削除
@echo off
rem 削除したいフォルダ: C:\very\deep\target

rem 空のテンポラリフォルダを用意
set "EMPTY_DIR=C:\empty_for_robocopy_%RANDOM%"
mkdir "%EMPTY_DIR%"

rem 空フォルダと同期(/purge で対象側に余分なファイルを削除)
robocopy "%EMPTY_DIR%" "C:\very\deep\target" /purge /e

rem テンポラリフォルダとターゲットを削除
rd "%EMPTY_DIR%"
rd /s /q "C:\very\deep\target"

if not exist "C:\very\deep\target\" (
    echo 削除完了
) else (
    echo エラー: 削除に失敗しました
)

エラーメッセージと対処法の対応表

エラーメッセージ 原因 推奨対処法
ファイル名が長すぎます MAX_PATH 超過 対処法①②③いずれか
The filename or extension is too long 同上(英語版 Windows) 同上
指定されたパスが見つかりません 長いパスをコマンドが処理できない \\?\プレフィックス or robocopy
The system cannot find the path specified 同上(英語版) 同上
コピー先フォルダが見つかりません コピー先もパス長超過の場合 コピー先を浅い場所に変更
xcopy が途中で失敗する xcopy は長いパス非対応 robocopy に切り替え

実践スクリプト:長いパスのファイルを安全にバックアップ

深いディレクトリ構造のプロジェクトを日付付きバックアップフォルダへコピーする実用的なスクリプトです。robocopy を使い、長いパスに対応しています。

backup_longpath.bat
@echo off
setlocal enabledelayedexpansion

if "%~1"=="" (
    echo 使い方: backup_longpath.bat "バックアップ元" "保存先ベース"
    echo 例: backup_longpath.bat "C:\deep\project" "D:\backup"
    exit /b 1
)

set "SRC=%~1"
set "DST_BASE=%~2"

if not exist "%SRC%\" (
    echo エラー: バックアップ元が見つかりません: %SRC%
    exit /b 1
)

rem タイムスタンプ生成
for /f "tokens=1-3 delims=/" %%a in ("%DATE%") do set "D=%%a%%b%%c"
for /f "tokens=1-2 delims=:." %%a in ("%TIME: =0%") do set "T=%%a%%b"
set "DEST=!DST_BASE!\backup_!D!_!T!"

echo バックアップ開始
echo  元: %SRC%
echo  先: !DEST!

rem robocopy で長いパスに対応したコピー
robocopy "%SRC%" "!DEST!" /e /copyall /256 /r:3 /w:5

rem robocopy: 0=変更なし 1=コピー成功 → どちらも成功
if %errorlevel% leq 1 (
    echo バックアップ完了: !DEST!
) else (
    echo エラー: バックアップ中に問題が発生しました (code=%errorlevel%)
    exit /b 1
)
endlocal

よくある質問(FAQ)

レジストリを変更できない環境(会社 PC など)で対処するには?
管理者権限不要の方法として、\\?\プレフィックス(②)、robocopy / PowerShell の利用(③)、subst による仮想ドライブ(④)が使えます。どれも一般ユーザー権限で実行可能です。
\\?\ プレフィックスを付けたのに動かないコマンドがある
xcopy\\?\ 非対応です。robocopy または PowerShell の Copy-Item -LiteralPath に切り替えてください。cd は動作しますが %CD% の値が意図しない形式になる場合があります。
robocopy の終了コードが 1 でもエラー扱いになってしまう
robocopy の終了コード 0 は「変更なし」、1 は「ファイルのコピー成功」でどちらも正常終了です。if %errorlevel% leq 1 (成功処理) else (失敗処理)のように判定してください。
subst で割り当てたドライブが再起動後に消える
subst の割り当てはセッション内のみ有効です。永続的に使いたい場合は、スタートアップフォルダにバッチを置くか、mklink /j によるジャンクション(④)を使ってください。
del でも rd /s /q でも削除できない深いフォルダがある
robocopy の /purge オプションで空フォルダと同期して削除する方法(本記事の「安全に削除する方法」参照)、またはPowerShell の Remove-Item -LiteralPath "パス" -Recurse -Force を使ってください。
日本語フォルダ名でも MAX_PATH の問題が発生するか?
発生します。MAX_PATH はバイト数ではなく文字数でカウントします。日本語1文字は UTF-16 で 2 バイトですが、パス長としては 1 文字とカウントされます。ただし、ファイルシステムの実際の格納は UTF-16 で行われるため、内部処理では 2 バイト分のコストがかかっている点に注意してください。

まとめ

Windowsのパス長制限(MAX_PATH=260文字)への対処法をまとめます。

  • 恒久的な解決: レジストリで LongPathsEnabled=1 を設定(Windows 10/11・管理者権限必要)
  • スポット対応: \\?\プレフィックスを付けてAPI経由で長いパスを処理
  • コピー・移動・削除: xcopy の代わりに robocopy または PowerShell の -LiteralPath を使う
  • 既存スクリプトの改修なし: subst で仮想ドライブを割り当ててパスを短縮
  • 削除できないフォルダ: robocopy /purge で空フォルダと同期して削除
  • 根本解決: ディレクトリ構造を浅くする・フォルダ名を短縮する

バッチファイルでのパス操作全般についてはパスのスペースエラー解決ガイドも合わせて参照してください。ファイルのコピーや削除コマンドの詳細はファイルをコピーする方法完全ガイドファイルを削除する方法完全ガイドをご覧ください。