まえがき
前回、大量の画像ファイルを年月フォルダに仕分けするところまではやった。その際に重複しているファイルを削除するための手がかりとして次のようなCSVファイルを各フォルダに生成した。
IMG_2607.jpg,BCF3E765,1944106
IMG_2607(1).jpg,BCF3E765,1944106
IMG_2608.jpg,02B27221,3109397
IMG_2608(1).jpg,02B27221,3109397
010(8).jpg,E4A68AB2,3801239
010(9).jpg,3EBBC7BD,1841698
010(10).jpg,B9431E60,103645
左からファイル名、CRC32、ファイルサイズとなっておりCRC32とファイルサイズが一致するファイルはほぼ間違いなく同じファイルであろうということで削除対象にする。前記のファイルで言えば2行目と4行目が重複しているのでこれを次のように2グループに分けたい。
IMG_2607.jpg,BCF3E765,1944106
IMG_2608.jpg,02B27221,3109397
010(8).jpg,E4A68AB2,3801239
010(9).jpg,3EBBC7BD,1841698
010(10).jpg,B9431E60,103645
IMG_2607(1).jpg,BCF3E765,1944106
IMG_2608(1).jpg,02B27221,3109397
考え方としては単純に削除リスト ← 元のリスト - 重複しているリスト
と生き残りリスト ← 元のリスト - 削除リスト
で良いのだが色々こねくり回してみたものの納得のいく実装に辿り着けなかったので今回は
- 空の生き残りリストと削除リストを用意する
- 検査対象が生き残りリストにあれば削除リストに追加する
- 検査対象が生き残りリストになければ生き残りリストに追加する
といったシンプルな実装にする(やりたいことが込み入った内容ではないのでこれで十分かと思っている)
開発環境
- OS : Windows10Home(1903)
- Editor:Visual Studio Code : 1.49.1
- Python : 3.8.3
- pandas : 1.0.5
コード
import os
import sys
import pandas as pd
def classify(path, target):
lines = pd.read_csv(os.path.join(path, target), header=None)
d = {}
servived_dict = {} # 生き残るもの
delete_dict = {} # 削除対象
# filename,crc32,filesizeを{filename, (crc32, filesize)}にする
for i in range(len(lines)):
(filename, crc32, filesize) = lines.values[i]
d[filename] = (crc32, filesize)
for key, value in d.items():
if value in servived_dict.values():
delete_dict[key] = value
else:
servived_dict[key] = value
def output(full_path, dic):
with open(full_path, mode='w') as f:
for key in dic.keys():
# 削除対象ファイルのフルパスだけ欲しいので
f.write(os.path.join(path, key) + "\n")
output(os.path.join(path, "servived.txt"), servived_dict)
output(os.path.join(path, "delete.txt"), delete_dict)
if __name__ == "__main__":
full_path = sys.argv[1]
classify(os.path.dirname(full_path), os.path.basename(full_path))
最初のfor文にて後で扱いやすいように検査対象を{filename, (crc32, filesize)}に変換している。タプルにしない場合CRC32とファイルサイズそれぞれが含まれているか検査することになるのでそれは少々ダサいかなと。あと、servived_dictは存在意義があるがservived.txtに出力しても使い道がないので出力は不要(とは言えデバッグ時には有用だった)
あとがき
まだまだにわかPythonistaなので多分集合演算でサクっと終わってしまうような気もしているが今回はこれにて。次は各年月フォルダに生成されたdelete.txtを参照して削除処理ですか(何で書こうかな・・)