クリーンアップ重複ファイルのPython実装

著作権:いいえ著作権は、https://blog.csdn.net/MAOZEXIJR/article/details/91551404への無料転載します

まず、シナリオが説明します

1、あまりにも多くのディスクファイル、彼らは、単に重複したファイルを一掃したい、あまりにも面倒なマニュアルを削除するには耐えることができませんでした

2、完成した製品をダウンロードしてください。

      Baiduのクラウド:https://pan.baidu.com/s/1W3pHU-dGi_mrd8M140Vogg 
      抽出コード:ji0r

 

3、最終用途:

      (1)repeat.exeフォルダにファイルを横断するように配置します。

      (2)ダブルクリック  repeat.exe

      (3)自動的に「指紋」情報記録ファイルを読み取るための1つにより、現在のすべてのフォルダおよびサブフォルダいずれかを横断  /RESULT/md5.hisを、複数行の同一の「フィンガープリント」はパス情報がされるファイルフォームで書かれ  /RESULT/record.log  。

      (4)カットするために、他の「コピー」しながら、元のファイルのほとんどを保持  /結果/ REPEATS /削除するかどうかを選択するユーザーのための準備ができて、フォルダを。

      深トラバーサル(5)より、「カトン」であってもよい早期横断中に第1、ファイルを大量に検索するファイル。

      大きなファイルに直面したとき(6)、状況を横断し、あまりにも多くの時間を要し、あなたが直接プログラムを閉じることができ、次回は、ファイルを介して横断効率を向上させ、無駄な労力を削減トラバース、トラバースを繰り返されることはありません。注:ファイルは削除しないでください  /RESULT/md5.hisを 

 

実行する前に:

 

観察/ルート/son.jpg及び /ルート/サブ/son.jpg互いに繰り返します

/ルート/grand.jpg及び  /ルート/プロモーター/日/grand.jpg相互に繰り返し

/ルートは/root.jpgない何の繰り返しを

(説明と区別の便宜上、フォルダの下のファイルのすべてのコピーの名前が変更されていない他のファイルに保存されています)

 

ランタイム:

 

実行した後:

結果は/ルート/son.jpgのコピー /ルート/サブ/son.jpg 

/ルート/grand.jpgコピー  /ルート/子/日の/grand.jpgは に移動さ/ルート/結果/ REPEATS /フォルダ

ユーザーは、これらのファイルのコピーを削除するかどうかを選択できます

 

第二に、需要分析

同じファイルが存在する可能性が繰り返し、ファイル名が同じであってもよい、(「(2)XX」、最古の作成日時、ファイル名ではなく、「コピー」以外の)彼らは、元のファイルを保存したい、異なる場合があります

同じファイルの2つのファイルかどうかを判断するには?どのように正確に区別し、指紋などの身体を特定するには?

ファイルが多すぎ、単一のファイルには、どのように二次的に横断する際に横断最後の結果を再利用するために、あまりにも多くの時間を要するトラバースには大きすぎますか?

特定のファイルのパーミッションを回避するために、どのように全体の横断への影響の欠如?

プログラム・キャッシュ・ゴミを実行するには?

 

第三に、コードの実装

1、folder.py 

# !/usr/bin/python3
# coding: utf-8
import os

import tool


def deep_list(path):
    if not os.path.isdir(path):
        return list()

    try:
        fs = os.listdir(path)
    except PermissionError:
        print("PermissionError:", path)
        return list()

    info = list()
    for f in fs:
        fp = tool.join(path, f)
        if os.path.isfile(fp):
            info.append(fp)
        elif os.path.isdir(fp):
            info.extend(deep_list(fp))
    return info

 

2、file.py

# !/usr/bin/python3
# coding: utf-8
import hashlib
import os
import traceback


def md5(path):
    if not os.path.isfile(path):
        return None

    try:
        hashes = hashlib.md5()
        f = open(path, "rb")
        while True:
            b = f.read(1024)
            if not b:
                break
            hashes.update(b)
        f.close()

        md = hashes.hexdigest()
        print("%s : %s" % (path, md))
        return md
    except:
        traceback.print_exc()
        return None


def name_order(path):
    if not os.path.exists(path):
        return None

    path = str(path).lower().strip()
    info = os.stat(path)
    create = info.st_ctime_ns
    if info.st_atime_ns < create:
        create = info.st_atime_ns
    if info.st_mtime_ns < create:
        create = info.st_mtime_ns

    suf = os.path.splitext(path)[1]
    basename = os.path.basename(path)
    name = basename.replace(suf, "").strip()
    name = name.replace("(", "(")
    name = name.replace(")", ")")

    layer = len(path.split("\\"))

    return "_".join((suf, str(create), name, str(layer)))

 

3、tool.py

# !/usr/bin/python3
# coding: utf-8


def join(path, *paths):
    path = fmt(path)

    for p in paths:
        p = fmt(p)
        path += "\\" + p

    path = fmt(path)
    return path


def fmt(path):
    if path is None:
        return ""

    path = path.strip()

    while path.find("/") >= 0:
        path = path.replace("/", "\\")
    while path.find("\\\\") >= 0:
        path = path.replace("\\\\", "\\")

    return path

 

4、mei.py

# !/usr/bin/python3
# coding: utf-8
import os
import re
import sys

import tool


def IS_MEI(basename):
    return re.match("^_MEI\d+$", basename) and True or False


def remove():
    for index, path in enumerate(sys.path):
        basename = os.path.basename(path)
        if not IS_MEI(basename):
            continue

        drive = os.path.splitdrive(path)[0]
        if "" == drive:
            path = tool.join(os.getcwd(), path)

        if os.path.isdir(path):
            try:
                print("remove", path)
                os.remove(path)
            finally:
                break

 

5、repeat.py(コア)

# !/usr/bin/python3
# coding: utf-8
import gc
import os
import sys
import time
import traceback

this = os.path.abspath(os.path.dirname(__file__))
module = os.path.split(this)[0]
sys.path.append(module)
for i, val in enumerate(sys.path):
    print("[%s] %s" % (i + 1, val))

import file
import folder
import tool
import mei

SEGMENTER = ">>"

FOLDER_FOR_RESULT = "RESULT"
FOLDER_FOR_REPEATS = "REPEATS"

FILE_MD5_HIS = "md5.his"
FILE_MD5_TMP = "md5.tmp"
FILE_RECORD_LOG = "record.log"


def read_md5_his(cwd):
    his_path = tool.join(cwd, FOLDER_FOR_RESULT, FILE_MD5_HIS)
    if not os.path.exists(his_path):
        return dict()

    with open(his_path, 'r', encoding='utf-8') as f:
        lines = f.readlines()

    fpMd5 = dict()
    for line in lines:
        row = line.split(SEGMENTER)
        fp = row[0].strip()
        md5 = row[1].strip()
        if os.path.exists(fp) and len(md5) > 1:
            fpMd5[fp] = md5
    return fpMd5


def reverse_file_md5(fileMd5):
    ls = list()
    for fp, md5 in fileMd5.items():
        ls.append((fp, md5))
    ls.sort(key=lambda ele: ele[1])

    md5Fp = dict()
    for kv in ls:
        fp = kv[0]
        md5 = kv[1]

        if md5 not in md5Fp:
            fps = set()
        else:
            fps = md5Fp[md5]
        fps.add(fp)
        md5Fp[md5] = fps

    return md5Fp


def scan_folder(cwd):
    # step0: listdir
    fps = folder.deep_list(cwd)
    if len(fps) < 2:  # must have it self
        print("No FILE IN", cwd)
        return

    # step1: remove self and root_folder
    self = os.path.abspath(sys.executable)
    print("SELF IS", self)
    if self in fps:
        fps.remove(self)

    result_path = tool.join(cwd, FOLDER_FOR_RESULT)
    for index in range(len(fps) - 1, -1, -1):
        fp = fps[index]
        if str(fp).startswith(result_path):
            fps.remove(fp)

    if len(fps) < 1:
        print("No FILE IN", cwd)
        return

    # step2: read history and write to tmp
    tmp_path = tool.join(cwd, FOLDER_FOR_RESULT, FILE_MD5_TMP)
    fpMd5 = read_md5_his(cwd)
    if len(fpMd5) > 0:
        rows = ""
        for p, md5 in fpMd5.items():
            rows += p + SEGMENTER + md5 + "\n"
        with open(tmp_path, 'w', encoding='utf-8') as f:
            f.write(rows)

    print()

    # step3: makedir
    repeats_path = tool.join(cwd, FOLDER_FOR_RESULT, FOLDER_FOR_REPEATS)
    if not os.path.exists(repeats_path):
        os.makedirs(repeats_path)

    fps = list(fps)
    fps.sort(key=lambda fp: os.stat(fp).st_size, reverse=True)

    # step4: read file's md5 and append to tmp
    tmpMd5 = dict()
    for index in range(len(fps)):
        fp = fps[index]
        if fp in fpMd5:
            continue

        md5 = file.md5(fp)
        if md5 is not None:
            tmpMd5[fp] = md5
            fpMd5[fp] = md5

        if 10 == len(tmpMd5) or (index == len(fps) - 1):
            rows = ""
            for p, md in tmpMd5.items():
                rows += p + SEGMENTER + md + "\n"
            with open(tmp_path, 'a', encoding='utf-8') as f:
                f.write(rows)
            tmpMd5.clear()

    print()

    # step5: remove the repeat
    content = ""
    md5Fp = reverse_file_md5(fpMd5)
    for md5, fps in md5Fp.items():
        if len(fps) < 2:
            continue

        fps = list(fps)
        fps.sort(key=lambda fp: file.name_order(fp))

        print("%s : %s" % (md5, ','.join(fps)))
        content += ','.join(fps) + "\n"

        for i in range(len(fps)):
            if i == 0:
                # not move the first
                continue

            old = fps[i]
            fn = os.path.basename(old)
            new = tool.join(repeats_path, fn)
            if old == new:
                continue

            # if the new is exist
            if os.path.exists(new):
                try:
                    os.remove(new)
                except:
                    traceback.print_exc()

            # move the repeats to REPEAT/FILES folder
            try:
                os.rename(old, new)
            except:
                traceback.print_exc()

    # step6: record the repeat
    if "" == content:
        print("No REPEAT FILE EXISTS")
    else:
        this_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))

        record = tool.join(cwd, FOLDER_FOR_RESULT, FILE_RECORD_LOG)
        with open(record, 'a', encoding='utf-8') as f:
            f.write("\n\n" + this_time + "\n" + content)


def save_file_md5(cwd):
    # step7: update md5 history record file
    try:
        his_path = tool.join(cwd, FOLDER_FOR_RESULT, FILE_MD5_HIS)
        tmp_path = tool.join(cwd, FOLDER_FOR_RESULT, FILE_MD5_TMP)

        if os.path.exists(tmp_path):
            if os.path.exists(his_path):
                os.remove(his_path)
            os.rename(tmp_path, his_path)
    except:
        traceback.print_exc()


if __name__ == '__main__':
    try:
        cwd = os.getcwd()
        print("\nCURRENT PATH IS %s\n" % cwd)

        scan_folder(cwd)
    except:
        traceback.print_exc()
    finally:
        save_file_md5(cwd)

        gc.collect()
        input("\nPRESS ANY KEYS TO EXIT\n")
        mei.remove()

 

第四に、パッケージexeファイル

pyinstaller -F repeat.py

部門は、詳細は、詳細を参照してくださいことはありません。

「pyInstallerのパッケージ教訓しました」

「pyInstallerのexeファイルの完全な一時をパッケージ化」

おすすめ

転載: blog.csdn.net/MAOZEXIJR/article/details/91551404
おすすめ