[AHK] ファイルコピーで進捗状況を表示
2018/10/04
大きなファイルをコピーするときには、コピーの進捗状況を表示できると便利ですよ。
フリーズかと見紛う FileCopy
AutoHotkeyでファイルコピーをする場合、通常FileCopyコマンドを使用します。しかし、コピーするファイルサイズが大きかったり、ドライブの速度が遅かったりすると、ファイルコピーしている間AutoHotkeyスクリプトは何の反応もしなくなります。
特にGUIを持つスクリプトの場合、裏ではコピーが実行されているのにGUIはWindowsに「応答なし」と判断されてしまうため、スクリプトがフリーズしたのか区別できなくなります。
進捗状況を表示できるファイルコピー方法
AutoHotkeyの標準コマンドだけでは進捗情報付きのファイルコピーはできません。そこでDllCallでCopyFileExを呼び出します。
; pSourceFilePath: コピー元ファイルパス ; pDestFilePath : コピー先ファイルパス FileCopyProgress(pSourceFilePath, pDestFilePath) { global cancelFlag, gSourceSize, gCopiedSize, gProgressSizePrev callbackAdr := RegisterCallback("CopyProgressRoutine", "Fast") VarSetCapacity(cancelFlag, 1, 0) FileGetSize, gSourceSize, %pSourceFilePath% gCopyingFile := pSourceFilePath gCopiedSize:= 0 gProgressSizePrev := 0 DllCall( "CopyFileEx" , "WStr", pSourceFilePath , "WStr", pDestFilePath ".part" , "Ptr", callbackAdr , "Int", 0 , "UInt", &cancelFlag , "UInt", 0x00000000 ) FileMove, %pDestFilePath%.part, %pDestFilePath% } CopyProgressRoutine(pFullSize, var2, pProgressSize, var4) { global gSourceSize, gCopiedSize, gProgerssSizePrev ; pFullSize: 転送中のブロック全体のサイズ ; pProgressSize: ブロック中のコピー済みファイルサイズ if(pProgressSize < gProgressSizePrev) gCopiedSize += gProgressSizePrev gProgressSizePrev := pProgressSize copiedMB := Round((pProgressSize + gCopiedSize) / 1024 / 1024, 1) sourceMB := Round(gSourceSize / 1024 / 1024, 1) percent := Round((pProgressSize + gCopiedSize) / gSourceSize * 100, 1) GuiControl, , editHoge, %copiedMB%MB / %sourceMB%MB 完了 GuiControl, , editFuga, %percent% `% }
ファイルコピー中に CopyProgressRoutine 関数が繰り返し呼ばれます。この中にGuiControlなどでGuiの書き換え処理を書いておけば、進捗を表示できます。
コピー失敗対策付き
コピーが開始されるとコピー先にファイルが作成されます。何らかの要因(スクリプトを強制終了する、PCの電源が落ちる など)で処理が中断されてしまうと、コピー途中なのにファイルが作成されていて、コピーがちゃんと完了しているのか分からなくなってしまいます。
そこでコピー処理では宛先ファイル名に「.part」を付加してコピーが途中であることを明示しておきます。コピーがちゃんと完了したら、宛先ファイル名から「.part」を外します。コピー途中で処理が中断してしまうと「.part」ファイルのままになっているのでコピーが失敗したことが分かります。こうなった場合は「.part」付きファイルは削除して改めてコピー処理を始めます。
コピーのキャンセル可能
CopFileEx にはキャンセルフラグの指定ができるので、cancelFlag を 1 にするとその時点でファイルコピーを中断できます。
注意点
CopyFileEx の仕様として、約3.8GB以上のファイルは約3.8GB単位に分割されて処理されます。このとき CopyProgressRoutine に渡される pFullSize と pProgressSize は分割単位のサイズです。
3.8GB以上のファイルをコピーする場合の対策として、全体サイズを事前取得し、コピー済みサイズ取得にちょっとした工夫を入れています。