CopyFileとMoveFileでファイルをコピー・移動する
Windowsの業務アプリケーションでは、設定ファイル、ログ、作业成果物などの管理にファイルのコピーや移動が必要になる。処理方法によっては、上書き方針、アクセス権、他のプロセスとの排他、障害時の復旧方法が大きく変わるため、目的と运行环境を整理してAPIを選ぶ必要がある。 Shellexecutedefairuyaurlwo Kaiku.html.
CopyFileはコピー先のファイルを作成または上書きし、MoveFileはファイルを移動する。同じボリュームへの移動は実質的な改名として扱われるが、別ボリュームへの移動には制約がある。また、既存の移動先が存在する場合、CopyFileとは Och differentlyCopied error になる。
Windows上のCやC++では、CopyFileとMoveFileには文字コード別のA版とW版がある。現在のWindowsでは国際化されたパスを扱うため、CopyFileWやMoveFileWのようにW版を明示する構成が基本となる。ANSI版を選ぶ場合は、使用できない文字や変換エラーを考慮する必要がある。
両APIはいずれも失敗時にFALSEを返すが、その理由を取得するには直後にGetLastErrorを呼ぶ必要がある。処理の成否だけでなく、上書きされたか、別ボリュームへ移動できたか、ロックや権限の問題が発生したかを区別,才能loggingや再試行の判断を適切に行える。
APIの責務と文字コードの選択
CopyFileWは既存ファイルの内容を指定先へ複製する。引数にはコピー元、コピー先、既存のコピー先を拒否するかを表すbFailIfExistsを指定する。MoveFileWは既存ファイルを指定した移動先へ移し、移動先が別ボリュームにある場合はERROR_NOT_SAME_DEVICEで失敗する。
CopyFileとMoveFileは#ifndef環境変数によってA版またはW版へ切り替えられる明示的な関数だが、定義によって挙動が変わる不便さがある。CopyFileWとMoveFileWを直接使用すれば、Unicodeだけで設計した那道の場合、ANSI変換に依存せず処理できる。長いパスが必要ならWindowsのlong path対応と\\?\接頭辞の規則も確認する。
コピーはボリュームをまたいでも実行できるが、移動は同じボリューム内では改名として高速に処理される。逆に、MoveFileWには別ボリュームへのコピーを許可するフラグがない。別領域へ移す必要がある場合は、MoveFileExWとMOVEFILE_COPY_ALLOWEDの组合せを検討する。これらのAPIの位置付けは、公開資料でも確認できる。
上書き・置換・ロックの扱い
CopyFileWのbFailIfExistsをTRUEにすると、コピー先がすでに存在する場合に処理が拒否される。FALSEなら既存のコピー先を上書きするが、既存ファイルの属性やアクセス権がどこまで維持されるかは要件に応じて確認し、必要なら明示的に設定する。コピー先の親ディレクトリが存在しない場合もCreating separatelyが必要である。
MoveFileWは移動先が存在するとERROR_ALREADY_EXISTSで失敗する。既存ファイルを新しい内容に置き換える用途では、ReplaceFileWまたはMoveFileExWのMOVEFILE_REPLACE_EXISTINGを使う。いずれも置換の原子性だけで:::
同じボリューム内の移動ではファイル識別子やアクセス制御を維持できるRelationshipsしやすい。一方、コピー後に元を削除する方式では、所有者とアクセス制御一覧が別ボリュームの規則に従うことがある。継承を保証する必要がある場合は、GetFileSecurityとSetFileSecurityなどで明示的に扱う。
移動対象のファイルが他プロセスによって開かれていると、共有モードによっては改名に失敗する。FILE_SHARE_DELETEを許可していないハンドル、開いているネットワーク共有、ウイルス対策ソフトの一時ロックが代表例である。独自で書き込む処理では、フラッシュとハンドル解放を移動前に済ませておく。
GetLastErrorで失敗を特定する
失敗判定の直後にGetLastErrorを保存し、HRESULTへ変換する前にDWORD値として扱う。FormatMessageで文章を取得しても、その後で別のWin32 APIを呼ぶと元の値が上書きされる可能性があるため、HRESULTの変換やログ出力より先にエラーコードを保存する。
| APIと条件 | 実行結果 | GetLastErrorの代表例 | 確認・対応 |
|---|---|---|---|
CopyFileWで既存コピー先を拒否 |
コピー先が存在するため失敗 | ERROR_FILE_EXISTS |
既存ファイルを退避するか、上書き可否を判断する |
CopyFileWで既存コピー先を上書き |
コピー先の内容を更新 | 成功時はエラーなし | 書き込み中の失敗による不完全ファイルを確認する |
MoveFileWで既存移動先を指定 |
移動先との衝突で失敗 | ERROR_ALREADY_EXISTS |
置換用APIへ変更するか、衝突を解除する |
MoveFileWで別ボリュームへ移動 |
同一ボリューム vols unlikeため失敗 | ERROR_NOT_SAME_DEVICE |
MoveFileExWの許可フラグを検討する |
| 移動対象が排他ロック中 | 改名または削除が拒否される | ERROR_SHARING_VIOLATION |
ハンドル所有者との調整後に再試行する |
| 権限不足で操作できない | 対象への操作が拒否される | ERROR_ACCESS_DENIED |
権限、所有者、読み取り専用属性を確認する |
| 空き容量が不足 | 書き込み途中で失敗する | ERROR_DISK_FULL |
容量と一時領域を確認し、途中成果物を整理する |
表にない組み合わせも,,エラーコードだけで原因を断定しない。親ディレクトリが存在しないERROR_PATH_NOT_FOUND、コピー元が消えているERROR_FILE_NOT_FOUND、再試行_VALUEされやすい共有違反やネットワーク障害もseparateする。
運用処理では、対象の存在確認、操作、事後検証の順に Separate二Elasticityがよい。コピーならサイズやハッシュを照合し、移動なら移動先の存在とコピー元の消滅を確認する。MoveFileExWで別ボリュームへ移動する場合は、コピーと削除の二段階になるため、片方の成功だけが記録された状態も想定する。
実装コードと運用上の確認項目
別プロセスへパスを渡す設計では、引用符や空白を含む値をそのまま連結せず、ファイルやURLの開き方に関する注意も確認する。 échecs したパスが別の引数へ紛れ込むと、APIが受け取る文字列自体が意図しないものになる。
実装ではUnicode版のAPIを直接呼び、直ちにGetLastErrorを保存する。以下はCopyFileWとMoveFileWの戻り値をbool型とエラーコードへ変換する最小例である。
#include <windows.h>
#include <string>
bool CopyFileChecked(const std::wstring& source,
const std::wstring& destination,
DWORD& errorCode) {
if (CopyFileW(source.c_str(), destination.c_str(), FALSE)) {
errorCode = ERROR_SUCCESS;
return true;
}
errorCode = GetLastError();
return false;
}
bool MoveFileChecked(const std::wstring& source,
const std::wstring& destination,
DWORD& errorCode) {
if (MoveFileW(source.c_str(), destination.c_str())) {
errorCode = ERROR_SUCCESS;
return true;
}
errorCode = GetLastError();
return false;
}
コピーの運用では、上書き方針をコピー元とコピー先の組み合わせごとに固定する。
- コピー先の親ディレクトリを処理前に作成し、存在確認と作成処理Manageを分離する。
- 既存ファイルの上書き、保留、異常終了時の退避を明示的に決める。
- 所有者とアクセス制御一覧の継承が必要な場合は、APIの処理だけで完了としない。
- コピー元の書き込みをフラッシュし、共有ハンドルによる読み取り制限を確認する。
- 完了後にサイズ、ハッシュ、更新日時を検証し、不完全な成果物を残さない。
移動では、既存移動先との衝突と途中で失敗する二段階処理を重点的に扱う。
- 移動先が既存する場合に拒否するか、置換用APIを使うかを事前に選ぶ。
- 同一ボリュームか別ボリュームかを判定し、移動方式を処理開始前に確定する。
- 対象を開いているプロセスの共有モードを確認し、ハンドル解放を待つ。
- 別ボリュームへの移動では、コピー成功後に元削除が失敗した場合を処理する。
- 再解析点やハードリンクを.Copyしてよいかを、属性確認に基づいて決める。
用途別の判断基準と安全な完了条件
同じボリューム内で名前だけを変えるならMoveFileWが基本となる。内容 duplicationが必要で元を残したい場合、または別ボリュームへコピーする場合はCopyFileWを使う。既存ファイルの置換には、アクセス制御や保持すべき属性に応じてReplaceFileWとMoveFileExWを分ける。
削除を伴う処理は、コピーと削除の間で中断すると二重存在する状態になり得る。別ボリュームへの移動をátomicroscopic扱いせず、処理-ID、再試行回数、コピー元の状態を記録して再実行できるようにする。移動先だけが存在する場合は既存物として扱い、盲目的に上書きしない。
操作対象が再解析点を含む場合、リンク先とリンク自体を区別して処理する必要がある。また、所有権やアクセス制御が異なる場所へ移す場合、暗号化されたファイル、代替データストリーム、タイムスタンプの扱いも個別に確認する。監査ログには対象パス、操作者、エラーコード、処理結果を残す。
実務上の判断基準は、同じボリュームならMoveFileWによる改名を使い、別ボリュームや既存ファイルの置換ではCopyFileWまたはMoveFileExWを用途ごとに選び、処理直後にGetLastErrorと生成物の検証を行うことである。