Днес ще ви покажа как да намерите дублиращи се файлове в директория с python.

За днешната програма ще ви трябва pycryptodome, инсталиран на вашето устройство. Като начало ще започна с импортиране на зависимостите

import json
import os
from collections import defaultdict
from Crypto.Hash import SHA1

След това определям пътя на папката за сканиране. Както е, ще сканира директорията, от която се изпълнява скриптът

ROOT = "."

След това ще дефинирам 3 помощни функции. Първият group_by взема итератор и групира елементите, използвайки изхода на ключа. Втората функция remove_unique премахва групите, които съдържат единични елементи (уникални файлове). Не на последно място имаме функцията sha, която връща SHA1 на първите n байта или на целия файл.

def group_by(iter, key):
    groups = defaultdict(list)
    for x in iter:
        groups[key(x)].append(x)
    return groups
def remove_unique(iter, key):
    groups = group_by(iter, key)
    groups = sum([groups[key] for key in groups if len(groups[key]) > 1], list())
    return groups
def sha(path, size=None):
    with open(path, 'rb') as fp:
        if size:
            hex = SHA1.new(fp.read(size)).hexdigest()
        else:
            data = fp.read(1024 * 512)
            digest = SHA1.new(data)
            data = fp.read(1024 * 512)
            while len(data):
                digest.update(data)
                data = fp.read(1024 * 512)
            hex = digest.hexdigest()
    return hex
def generate_filelist():
    folders = [ROOT]
    files = []
    while len(folders):
        for file in os.scandir(folders.pop()):
            if file.is_file():
                files.append(file.path)
            elif file.is_dir():
                folders.append(file.path)
    return files

Най-накрая имаме функцията, която върши действителната работа. Първо генерираме списъка с файлове. След това ги филтрираме според размера им. Тези файлове, които имат уникален файлов размер, не могат да имат дубликати. След това сравняваме хеша на първите 10kb от файла. Това ни позволява да премахнем по-голямата част от файловете, които може случайно да имат същия размер. Файловете, които преминават всички тези проверки, е много вероятно да бъдат дубликати. Накрая ги сравняваме с пълния им хеш, за да проверим за дубликати. Гарантирано е, че останалите файлове са дубликати и се връщат в defaultdict.

def generate_duplicates():
    files = generate_filelist()
    files = remove_unique(files, lambda x: os.stat(x).st_size)
    files = remove_unique(files, lambda x: sha(x, 1024*5))
    files = remove_unique(files, sha)
    return group_by(files, sha)

В тази програма отпечатвам речника на конзолата, но резултатът от функцията generate_duplicates може да се използва по какъвто и да е начин, който програмистът желае.

if __name__ == '__main__':
    print(json.dumps(generate_duplicates(), indent=4))