このサイトでは、分析、カスタマイズされたコンテンツ、および広告に Cookie を使用します。このサイトを引き続き閲覧すると、Cookie の使用に同意するものと見なされます。
Hi, Developers,
straightapps.com
投稿 November 15, 2018、更新 April 26, 2019(様式変更)
トップページ > Windows トップ > DupliFileDetector

Windows 開発

DupliFileDetector は、指定のフォルダ(およびサブフォルダ)にある重複ファイルを検出するユーティリティです。

スマートフォンやデジカメで撮影した写真やビデオは、PCに取り込んでバックアップ・管理しますが、 スマホやカメラで見たいこともあり、一部または全部をメモリーカードに残しておくことがあります。 また、地図やパンフレットなどの PDF ファイルをダウンロードして保存することもありますが、 保存先を忘れて同じものをダウンロードしてしまうこともあるでしょう。

すると、どうしても重複してハードディスクに取り込んでしまうファイルが出てきます。 それを探すのは面倒なわけですが、ファイル名が異なっている(別名で保存していまっている)場合には、もっと大変です。 放置すればHDD容量を圧迫していきますし、重複保存していると思って削除したら重複していなかった、となるとショックです。

この手のツールは探せばすぐ見つかりますが、簡単な構造ですから、自作しました。 ツールとしてというより、忘れやすいコードを中心に、ここに記載しています。

このページにトピック一覧がありますので、あわせてご参照ください。
ご利用に際しては、必ずプライバシーポリシー(免責事項等)をご参照ください。

このプログラムの目的

投稿 November 15, 2018

特に画像やビデオといったデータ種別(フォーマット)にとらわれることなく、 指定のフォルダ(およびそのサブフォルダ)にあるファイルを検索し、重複ファイルを検索します。

同一ファイル名のものであれば、(相当古いマイクロソフトのツール)WinDiff などのユーティリティを使ってフォルダ単位で比較できますが、 ファイル名が変わっていたり、タイムスタンプが変わっていると、そう簡単にはいきません。

このプログラムは、指定したフォルダ(オプションでサブフォルダも含められます)にあるファイルをすべて検査し、 ファイル名、拡張子、タイムスタンプなどすべて関係なく、 バイナリ ( バイト単位のデータとして比較した結果になります。 ) として同一のファイルがあれば、 それを検出して教えてくれる、というものです。

ツール系ではよく使う、「参照...」ボタンからのフォルダの指定、 あるいはエクスプローラ等からのドロップ受付処理、 フォルダを(エクスプローラで)開く処理、ファイルを(関連付けられたプログラムで)開く処理などのコードが含まれています。 また、長い処理に入ったときの中止処理を、(このプログラムはちゃんとしていませんが)入れてあります。
Win7 + Visual C++ 2013/MFC で、ダイアログアプリとして作成しています。

▲ページ先頭へ

どんな動作をするのか

投稿 November 15, 2018

起動すると、次のような画面が表示されます。

左上の「検索対象フォルダ」欄に、検索対象のフォルダ名を入力します。 ドライブのルート ( C:\ や D:\ などです。 ) は指定できないようになっています。
すぐ右の「参照...」ボタンを押してフォルダを選択するか、このダイアログにフォルダをドロップしても入力できます。

サブフォルダも検索したい場合は、「サブフォルダを含める」にチェックを入れます。 初期状態はチェックされていない(サブフォルダを含めない)設定となっています。 なお、サブフォルダも検索する場合、処理時間が長くなる可能性がありますので、注意が必要です。

「検出する」ボタンを押すと、右側の空欄(リストボックス)に見つかったファイルがリストアップされ、 完了すると消去され、すぐ続けて重複ファイルの検索が始まり、その結果が出力されます。

重複ファイル数とそのファイル名(最初に見つかったもの)が表示されますので、ダブルクリックで詳細を見られます。

ダブルクリックで新しいダイアログが開き、 2つのファイルが重複している場合(同一ファイルが2つある場合)、次のようにリストに2アイテムが表示されます。

1つを選択して「フォルダを開く」ボタンを押すと、そのファイルを含むフォルダが開かれます。 アイテムをダブルクリックすると、関連付けられたプログラムでそのファイルを開きます。
「閉じる」ボタンを押して前の画面に戻り、「選択項目を削除」すると、結果リストからその項目が削除されます。

いずれの場合も、ファイル自体は削除されません。
本プログラムでは同一であると結論付けていますが、本当に削除するかどうかはあくまで使用者の責任となります。

なお、私なら、完全に信用できるサイト以外からのダウンロードはしませんが、 興味がある方のために、実行ファイルを圧縮したものを置いておきます。 安全に努めているマシンで用意したファイルですが、お試しいただく場合は、完全に自己責任でお願いします。
OSは Windows 7 以降、ランタイムなど環境の用意は 特に必要ない ( MFC ライブラリはスタティックリンクしています。 ) と思います。

実行ファイルを含む zip ファイルのダウンロードは、こちらです。
正しい zip ファイルのタイムスタンプは 2018/11/15 11:59:29、 正しい実行ファイルのタイムスタンプ(更新日時)は 2018/11/15 11:54:27 で、 zip 内は実行ファイル1つだけです。 zip ファイルサイズは 1,859,391 バイト、 実行ファイルのサイズは 3,333,632 バイトです。 パスワードは設定していません。

▲ページ先頭へ

フォルダを選択してもらう

投稿 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つ以上を受け付けなくしていますので、最後の部分でループでまわす必要はありませんが、 影響はありませんので、このままとしています。

▲ページ先頭へ

処理を中断したいとき

投稿 November 15, 2018

特に「サブフォルダを含める」にチェックを入れて検索を行ったとき、 重複ファイル数が多かったり、ビデオなどの大きいサイズのファイル比較が多くあった場合など、 長時間かかる場合があります。

基本的には、自分のみ利用するツールとして開発していますので、ワーカースレッドを作成して中断可能、のようにはしていません。 しかし、開発中など検索を中断したいケースもありました。そこで、非常に簡易的に、中断できる仕組みを入れてあります。

検索処理が長くなり、中断したいとき、もう1回この実行ファイルを起動すると、すでに起動されていることを検出し、 中断イベントを発行するか、問い合わせが行われます。中断イベントを発行すると、ループ内でそれを検知して中断する、 という仕組みになっています。

詳細は、「イベントによる簡易的な処理中止指示」をご覧ください。

▲ページ先頭へ

その他のコード

投稿 November 15, 2018

その他のコードは、別ページに分離して書いています。各リンクより、トピックに飛べるようになっています。

エクスプローラーでフォルダを開くコードは、「フォルダやファイルを開く」の ここに、 関連付けられたプログラムでファイルを開くコードは、上と同じトピック内のここに書いています。

▲ページ先頭へ


関連トピックス

関連トピックはありません。


その他のおすすめ

おすすめ記事はありません。



© 2017-2019 StraightApps.com 無断転載を禁じます。No reproduction without permission.