Natural Intelligence による記事要点まとめ
・ストレージにある同一ファイルを探すのは面倒である。
・ドロップしたフォルダ内の同一バイナリを検索できる。
・必要なコードの例をここに記載している。
スマートフォンやデジカメで撮影した写真やビデオは、PC に取り込んでバックアップ・管理しますが、 スマホやカメラで見たいこともあり、一部または全部をメモリーカードに残しておくことがあります。 また、地図やパンフレットなどの PDF ファイルをダウンロードして保存することもありますが、 保存先を忘れて同じものをダウンロードしてしまうこともあるでしょう。
すると、どうしても重複してハードディスクに取り込んでしまうファイルが出てきます。 それを探すのは面倒なわけですが、ファイル名が異なっている(別名で保存していまっている)場合には、もっと大変です。 放置すれば SSD/HDD 容量を圧迫していきますし、重複保存していると思って削除したら重複していなかった、となるとショックです。
この手のツールは探せばすぐ見つかりますが、簡単な構造ですから、自作しました。 ツールとしてというより、忘れやすいコードを中心に、ここに記載しています。
なお、Windows 開発に関する記事は 「Windows トップ」にトピック一覧がありますので、あわせてご参照ください。
なお、本サイトのご利用に際しては、必ずプライバシーポリシー(免責事項等)をご参照ください。
投稿 November 15, 2018
特に画像やビデオといったデータ種別(フォーマット)にとらわれることなく、 指定のフォルダ(およびそのサブフォルダ)にあるファイルを検索し、重複ファイルを検索します。
同一ファイル名のものであれば、(相当古いマイクロソフトのツール)WinDiff などのユーティリティを使ってフォルダ単位で比較できますが、 ファイル名が変わっていたり、タイムスタンプが変わっていると、そう簡単にはいきません。
このプログラムは、指定したフォルダ(オプションでサブフォルダも含められます)にあるファイルをすべて検査し、
ファイル名、拡張子、タイムスタンプなどすべて関係なく、
同一画像であっても JPEG と PNG や、PNG と BMP などではバイナリが異なりますから、検出されません。
ツール系ではよく使う、「参照...」ボタンからのフォルダの指定、
あるいはエクスプローラ等からのドロップ受付処理、
フォルダを(エクスプローラで)開く処理、ファイルを(関連付けられたプログラムで)開く処理などのコードが含まれています。
また、長い処理に入ったときの中止処理を、(このプログラムはちゃんとしていませんが)入れてあります。
Win7 + Visual C++ 2013/MFC で、ダイアログアプリとして作成しています。
投稿 November 15, 2018
起動すると、次のような画面が表示されます。
左上の「検索対象フォルダ」欄に、検索対象のフォルダ名を入力します。
すぐ右の「参照...」ボタンを押してフォルダを選択するか、このダイアログにフォルダをドロップしても入力できます。
サブフォルダも検索したい場合は、「サブフォルダを含める」にチェックを入れます。 初期状態はチェックされていない(サブフォルダを含めない)設定となっています。 なお、サブフォルダも検索する場合、処理時間が長くなる可能性がありますので、注意が必要です。
「検出する」ボタンを押すと、右側の空欄(リストボックス)に見つかったファイルがリストアップされ、 完了すると消去され、すぐ続けて重複ファイルの検索が始まり、その結果が出力されます。
重複ファイル数とそのファイル名(最初に見つかったもの)が表示されますので、ダブルクリックで詳細を見られます。
ファイル名をダブルクリックで新しいダイアログが開き、 2 つのファイルが重複している場合(同一ファイルが 2 つある場合)、次のようにリストに 2 アイテムが表示されます。
1 つを選択して「フォルダを開く」ボタンを押すと、そのファイルを含むフォルダが開かれます。 アイテムをダブルクリックすると、関連付けられたプログラムでそのファイルを開きます。
「閉じる」ボタンを押して前の画面に戻り、「選択項目を削除」すると、結果リストからその項目が削除されます。
いずれの場合も、ファイル自体は削除されません。
本プログラムでは同一であると結論付けていますが、本当に削除するかどうかはあくまで使用者の責任となります。 このツールを使用した結果について当サイトは一切責任を追いません。
なお、私なら完全に信用できるサイト以外からのダウンロードはしませんが、 興味がある方のために、実行ファイルを圧縮したものを置いておきます。 安全に努めているマシンで用意したファイルですが、お試しいただく場合は、完全に自己責任でお願いします。
OS は Windows 7 以降、ランタイムなど環境の用意は
実行ファイルを含む zip ファイルのダウンロードは、
https://www.straightapps.com/download/duplifiledetector.zip
から行えます。
上記 URL をブラウザで開くとダウンロードが始まります。
正しい zip ファイルのタイムスタンプは 2018/11/15 11:59:29、 正しい実行ファイルのタイムスタンプ(更新日時)は 2018/11/15 11:54:27 で、 zip 内は実行ファイル1つだけです。 zip ファイルサイズは 1,859,391 バイト、 実行ファイルのサイズは 3,333,632 バイトです。 パスワードは設定していません。
▼ Amazon 広告 ▼
Dropbox Plus 3 年版| クラウドサービス | Windows・Mac・Android・iOS 対応
WinZip 29 Standard(最新版) | ファイル圧縮・暗号化ソフト | Windows 対応
投稿 November 15, 2018
「参照...」ボタン処理で、フォルダの選択ダイアログを表示し、選択されたフォルダを取得しています。
次のようなコードを入れています。
#include "shlobj.h" void CDupliFileDetectorDlg::OnClickedBrowse() { BROWSEINFO bi; LPITEMIDLIST itemID; TCHAR szDir[MAX_PATH]; TCHAR szFile[MAX_PATH]; ZeroMemory(&bi, sizeof(BROWSEINFO)); ZeroMemory(szDir, MAX_PATH); ZeroMemory(szFile, MAX_PATH); bi.hwndOwner = GetSafeHwnd(); // オーナーウィンドウのハンドル bi.pidlRoot = NULL; // ルートフォルダのIDリスト bi.pszDisplayName = szFile; // 選択フォルダのパス bi.lpszTitle = _T("フォルダを選択して下さい"); // 表示テキスト bi.ulFlags = BIF_RETURNONLYFSDIRS; // フォルダのみ選択 bi.lpfn = NULL; // コールバック関数 bi.lParam = 0; // コールバック関数に渡される値 bi.iImage = 0; // 選択フォルダのイメージリストインデックス if (itemID = SHBrowseForFolder(&bi)){ SHGetPathFromIDList(itemID, szDir); CoTaskMemFree(itemID); SetDlgItemText(IDC_FOLDER_1, szDir); } }
GlobalFreePtr 関数を呼び出して itemID を解放すべきという記述をネットで見つけているのですが、 今はこの関数はありません。 今は CoTaskMemFree 関数 を使用して IDList を解放する、ということです。
なお、この SHBrowseForFolder 関数は「ファイルを開くダイアログのフォルダモード」であり、 Windows Vista 以降では IFileDialog 関数に FOS_PICKFOLDERS を指定して使うべき、とされているようです。
投稿 November 15, 2018
ファイルのドロップを受け入れるには、ダイアログのプロパティで Accept Files を True にしておく必要があります。
そのダイアログに WM_DROPFILES メッセージのハンドラーを追加して、受付処理を実装します。
void CDupliFileDetectorDlg::OnDropFiles(HDROP hDropInfo) { TCHAR szBuffer[MAX_PATH]; // ドロップされたファイル数を検査します。 UINT unDropped = DragQueryFile(hDropInfo, 0xFFFFFFFF, NULL, 0); if (unDropped < 1){ // 安全のため、ドロップファイルなしを除外します return; // 続きの処理は行いません } // 2つ以上のファイルがドロップされた場合は警告を表示します。 if (unDropped ≷= 2){ CString strMsg; strMsg.Format(_T("2つ以上のファイルがドロップされました。\n\n一度に検査できるのは1フォルダのみです。")); MessageBox(strMsg, _T("検索フォルダのドロップ"), MB_ICONEXCLAMATION | MB_OK); return; } // ドロップファイル処理 for (UINT i = 0; i < unDropped; i++){ // ファイルを順次検査 DragQueryFile(hDropInfo, i, szBuffer, MAX_PATH); // ドロップされたファイル名を取得 SetDlgItemText(IDC_FOLDER_1, szBuffer); // エディットコントロールに登録 } }
OnDropFiles 関数が受領したハンドル hDropInfo を使って、 ドロップされたファイル(フォルダ)数を取得し、ループ内でそれを取得しています。
2 つ以上を受け付けなくしていますので、最後の部分でループでまわす必要はありませんが、影響はありませんので、このままとしています。
▼ Amazon 広告 ▼
Visual C++ 2022 パーフェクトマスター (Perfect Master 188)
かんたん Visual C++[改訂 3 版] (プログラミングの教科書)
投稿 November 15, 2018
特に「サブフォルダを含める」にチェックを入れて検索を行ったとき、 重複ファイル数が多かったり、ビデオなどの大きいサイズのファイル比較が多くあった場合などは、長時間かかる場合があります。
基本的には、自分のみ利用するツールとして開発していますので、ワーカースレッドを作成して中断可能、のようにはしていません。 しかし、開発中など検索を中断したいケースもありました。そこで、非常に簡易的に中断できる仕組みを入れてあります。
検索処理が長くなり、中断したいとき、もう 1 回この実行ファイルを起動すると、すでに起動されていることを検出し、 中断イベントを発行するか、問い合わせが行われます。 中断イベントを発行すると、ループ内でそれを検知して中断する、という仕組みになっています。
詳細は、「イベントによる簡易的な処理中止指示」をご覧ください。
投稿 November 15, 2018
その他のコードは、別ページに分離して書いています。 各リンクより、トピックに飛べるようになっています。
エクスプローラーでフォルダを開くコードは 「フォルダやファイルを開く」 の ここに、 関連付けられたプログラムでファイルを開くコードは、上と同じトピック内のここに書いています。
DaysUntil は、指定の日まであと何日かを計算する Windows デスクトップ・ユーティリティです。日数の計算や、うるう年の判定コードなどが入っています。
PC から SD カードに転送した音楽データが見えない
Android 9.0 で、PC から SD カードに転送した音楽データが、Play Music アプリで見えない問題について、書いています。