Python高效率遍歷文件夾尋找重復文件


前言

為什么要寫這篇文章呢。。。主要還是業務中有個需求,遍歷一個將近200w數據的文件夾,大部分還都是視頻文件那種,但是這玩意用的次數還不多,做文件夾index也不是很ok,所以寫了一個腳本來處理這個問題,從而發現了自己的一些薄弱點,將其記錄下來,方便自己,也方便未來其他的兄弟使用

基本需求

  1. 把文件夾中的重復文件找出來
  2. 找出來之后用csv輸出,左邊是源文件,右邊是重復文件
  3. 效率不能差,不能直接撐爆內存,不能占用過多資源
  4. 檢測的文件夾和存放csv的地方可以自己定義,加上終端交互
  5. 重復文件篩選支持md5,大小等方式

需求分析

首先要分析一點,就是我們該如何去做重復文件的對比,並且效率還要高,首先網上過多的遞歸,os.walk的方法不可用,因為他們都會把遍歷到的內容直接做成一個大列表,塞到內存里面,數據量大很容易爆掉,並且還要進行MD5,或者是大小比對,這個就非常難纏了。

基礎想法

其實說白了,拿到所有文件列表file_list,把文件依次對比,這里我們可以用dict,分兩種情況

按照文件名和大小

設定兩個dict,例如record和dup,遍歷file_list,生成一個數組,比對其中的文件名和大小

按照大小和MD5值

設定兩個dict,例如record和dup,遍歷file_list,生成一個數組,比對其中的md5值和大小

具體代碼

閑話休提,我們開始寫代碼吧

定義遍歷函數代碼

首先定義遍歷文件夾的部分diskwalk.py

# coding: utf-8

__author__ = "lau.wenbo"


import os,sys


class diskwalk(object):
    def __init__(self, path):
        self.path = path
    def paths(self):
        path = self.path
        # 這里用了一個迭代器邏輯,防止所有數據塞內存爆掉
        path_collection = (os.path.join(root,fn) for root,dirs,files in os.walk(path) for fn in files)
        return path_collection

定義檢查md5值代碼

接着我們定義檢查md5值的一個邏輯checksum.py

# coding: utf-8

__author__ = "lau.wenbo"


import hashlib,sys

# 分塊讀MD,速度快

def create_checksum(path):
    fp = open(path)
    checksum = hashlib.md5()
    while True:
        buffer = fp.read(8192)
        if not buffer: break
        checksum.update(buffer)
    fp.close()
    checksum = checksum.digest()
    return checksum

定義主函數代碼

# coding: utf-8

__author__ = "lau.wenbo"


from checksum import create_checksum
from diskwalk import diskwalk
from os.path import getsize
import csv
import os
import sys
reload(sys)
sys.setdefaultencoding('utf8')


def findDupes(path):
    record = {}
    dup = {}
    d = diskwalk(path)
    files = d.paths()
    for file in files:
        try:
            # 這里使用了大小,文件名的對比方式,如果你需要MD5值的對比方式,可以打開下面的注釋
            #compound_key = (getsize(file),create_checksum(file))
            compound_key = (getsize(file), file.split("/")[-1])
            if compound_key in record:
                dup[file] = record[compound_key]
            else:
                record[compound_key]=file
        except:
            continue
    return dup


if __name__ == '__main__':
    path = sys.argv[1]
    csv_path = sys.argv[2]
    if not os.path.isdir(path) or not os.path.isdir(csv_path) or csv_path[-1] != "/":
        print u"參數不是一個有效的文件夾!"
        exit()
    else:
        path = path.decode("utf-8")
        print u"待檢測的文件夾為{path}".format(path=path)
        with open(u"{csv_path}重復文件.csv".format(csv_path=csv_path),"w+") as csvfile:
            # 源文件 重復文件
            header = ["Source", "Duplicate"]
            writer = csv.DictWriter(csvfile, fieldnames=header)
            writer.writeheader()
            print u"開始遍歷文件夾,尋找重復文件,請等待........."
            print u"開始寫入CSV文件,請等待........"
            for file in findDupes(path).items():
                writer.writerow({"Source":file[1],"Duplicate":file[0]})

結語

實現了哪些功能呢,哈哈,結尾來說一下,其實核心就是我用了一個列表生成器,加了一個迭代器,迭代器可是好東西,不會撐內存,不錯了,效率也還可以,200w數據判定也就20多分鍾,支持大數據量,如果有什么不懂的,可以郵件聯系我或者等待我的評論系統搞完,over
github地址在這: https://github.com/Alexanderklau/Amusing_python/tree/master/File_operation/repeat


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM