バックアップが正しく取れているか確認したい、あるいはプロジェクトフォルダーの新旧バージョンで何が変わったのかを調べたい、といった場面はよくあります。
目視で一つずつファイルを確認するのは時間がかかり、ミスも起きやすくなります。
今回は、AutoIt を使って 2つのフォルダーの中身を比較し、ファイルの違いをリストアップして報告するスクリプトを作成します。
完成したスクリプトの全コード
#include <MsgBoxConstants.au3>
#include <WinAPISys.au3>
#include <File.au3>
; ### メイン処理 ###
MsgBox($MB_OK, "フォルダーの選択", "最初に比較元となる「フォルダーA」を選択してください。")
Local $sFolderA = FileSelectFolder("【フォルダーA】を選択", "")
If @error Then Exit
MsgBox($MB_OK, "フォルダーの選択", "次に比較対象となる「フォルダーB」を選択してください。")
Local $sFolderB = FileSelectFolder("【フォルダーB】を選択", "")
If @error Then Exit
Local $aFilesA = _FileListToArray($sFolderA, "*", $FLTAR_FILES)
Local $aFilesB = _FileListToArray($sFolderB, "*", $FLTAR_FILES)
Local $sResult = ""
Local $sOnlyInA = ""
Local $sOnlyInB = ""
Local $sModified = ""
If IsArray($aFilesA) Then
For $i = 1 To $aFilesA[0]
Local $sCurrentFile = $aFilesA[$i]
If NOT FileExists($sFolderB & "\" & $sCurrentFile) Then
$sOnlyInA &= $sCurrentFile & @CRLF
Else
Local $bDataA = FileRead($sFolderA & "\" & $sCurrentFile)
Local $bDataB = FileRead($sFolderB & "\" & $sCurrentFile)
Local $iSizeA = BinaryLen($bDataA)
Local $iSizeB = BinaryLen($bDataB)
Local $tDataA = DllStructCreate("byte[" & $iSizeA & "]")
DllStructSetData($tDataA, 1, $bDataA)
Local $tDataB = DllStructCreate("byte[" & $iSizeB & "]")
DllStructSetData($tDataB, 1, $bDataB)
Local $pDataA = DllStructGetPtr($tDataA)
Local $pDataB = DllStructGetPtr($tDataB)
If _WinAPI_ComputeCrc32($pDataA, $iSizeA) <> _WinAPI_ComputeCrc32($pDataB, $iSizeB) Then
$sModified &= $sCurrentFile & @CRLF
EndIf
EndIf
Next
EndIf
If IsArray($aFilesB) Then
For $i = 1 To $aFilesB[0]
Local $sCurrentFile = $aFilesB[$i]
If NOT FileExists($sFolderA & "\" & $sCurrentFile) Then
$sOnlyInB &= $sCurrentFile & @CRLF
EndIf
Next
EndIf
If $sOnlyInA <> "" Then
$sResult &= "▼ フォルダーAにのみ存在するファイル:" & @CRLF & $sOnlyInA & @CRLF
EndIf
If $sOnlyInB <> "" Then
$sResult &= "▼ フォルダーBにのみ存在するファイル:" & @CRLF & $sOnlyInB & @CRLF
EndIf
If $sModified <> "" Then
$sResult &= "▼ 中身が異なるファイル:" & @CRLF & $sModified & @CRLF
EndIf
If $sResult = "" Then
$sResult = "2つのフォルダーは同一です。"
EndIf
MsgBox($MB_OK, "比較結果", $sResult)
デスクトップにテスト用のフォルダーとファイルを作成する
デスクトップにテスト用のフォルダーとファイルを作成して比較してみてください。
このスクリプトを実行すると、デスクトップに「Compare_Test」という親フォルダーが作成され、その中に「Folder_A」と「Folder_B」という2つのフォルダーが作られます。
これらのフォルダーには、比較テストで想定される以下の様なシナリオのファイルが配置されます。
- 両方に存在し、中身も同じファイル
- 両方に存在するが、中身が違うファイル
- Folder_A にだけ存在するファイル
- Folder_B にだけ存在するファイル
#include <MsgBoxConstants.au3>
; ### メイン処理 ###
; 1. デスクトップにテスト用の親フォルダーを作成
Local $sBaseFolder = @DesktopDir & "\Compare_Test"
Local $sFolderA = $sBaseFolder & "\Folder_A"
Local $sFolderB = $sBaseFolder & "\Folder_B"
DirCreate($sFolderA)
DirCreate($sFolderB)
; 2. 各シナリオに応じたテストファイルを作成
; --- シナリオ1: 両方に存在し、中身も同一のファイル ---
FileWrite($sFolderA & "\common_file.txt", "This is a common file.")
FileWrite($sFolderB & "\common_file.txt", "This is a common file.")
; --- シナリオ2: 両方に存在するが、中身が異なるファイル ---
FileWrite($sFolderA & "\modified_file.log", "Version 1")
FileWrite($sFolderB & "\modified_file.log", "Version 2")
; --- シナリオ3: Folder_A にだけ存在するファイル ---
FileWrite($sFolderA & "\only_in_A.ini", "Setting for A")
; --- シナリオ4: Folder_B にだけ存在するファイル ---
FileWrite($sFolderB & "\only_in_B.dat", "Data for B")
; 3. 完了を通知
MsgBox($MB_OK, "完了", "テスト用のフォルダーとファイルの作成が完了しました。")
ShellExecute($sBaseFolder) ; 作成した親フォルダーを開く
コードの詳しい解説
比較対象フォルダーの選択
スクリプトを実行すると、まず FileSelectFolder 関数が 2回呼び出され、ユーザーに比較したい 2つのフォルダー(フォルダーA、フォルダーB)を選択させます。
その後、_FileListToArray 関数を使い、それぞれのフォルダー直下にあるファイルの一覧を配列として取得します。
ファイルの比較処理
比較ロジックは、大きく 3つのステップで行われます。
片方のフォルダーにしか存在しないファイルの検出
For ループでフォルダーA の全ファイルをチェックし、FileExists を使って同じ名前のファイルがフォルダーB に存在するかを確認します。存在しなければ「フォルダーAのみに存在」と判断します。
逆のパターンも同様に、フォルダーB の全ファイルをチェックし、フォルダーA に存在しないファイルを探します。
中身が異なるファイルの検出
両方のフォルダーに同じ名前のファイルが存在する場合、その中身が同一かどうかをチェックサム(ファイル固有の「指紋」のようなもの)を計算して比較します。
このスクリプトでは、AutoIt の標準ライブラリWinAPISys.au3に含まれる_WinAPI_ComputeCrc32関数を使用します。この関数は低レベルな API を呼び出すため、以下の手順を踏みます。
- ファイルの読み込み:
FileReadで、比較したい2つのファイルの中身をそれぞれ変数に読み込みます。 - メモリーポインターの取得:
_WinAPI_ComputeCrc32は変数そのものではなく、データが格納されているメモリのアドレス(ポインター)を必要とします。DllStructCreateでデータと同じサイズのメモリ領域を確保し、DllStructSetDataでデータをコピー、DllStructGetPtrでその領域のポインターを取得します。 - チェックサムの計算と比較: 取得したポインターとデータのサイズを
_WinAPI_ComputeCrc32に渡し、チェックサムを計算します。2つのファイルのチェックサムが異なれば、中身が違うと判断します。
比較結果の表示
3つのステップで検出された差分を、$sResult という一つの変数にまとめていきます。差分があった項目だけを見出し付きで追加し、もし差分が一つもなければ「2つのフォルダーは同一です。」というメッセージを設定します。
最後に、完成したレポートを MsgBox で表示します。
まとめ
このスクリプトは、ファイル名だけでなく、ファイルの中身もチェックサムによって確実に比較するため、非常に信頼性の高い結果を得ることができます。
Windows API の関数を DllStruct と組み合わせて利用するテクニックは、より高度なスクリプトを作成する上で重要なスキルとなります。


コメント