写了个删除重复文件的脚本

2018-07-16 13:00:21 +08:00
 ucun

收了很多二次元图片,难免会有重复的。 写了个小脚本删除重复的。


#! /bin/env python
# -*- coding:utf-8 -*-

import sqlite3
import hashlib
import os
import sys

def md5sum(file):
    md5_hash = hashlib.md5()
    with open(file,"rb") as f:
        for byte_block in iter(lambda:f.read(65536),b""):
            md5_hash.update(byte_block)
    return md5_hash.hexdigest()

def create_hash_table():
    if os.path.isfile('filehash.db'):
        os.unlink('filehash.db')
    conn = sqlite3.connect('filehash.db')
    c = conn.cursor()
    c.execute('''CREATE TABLE FILEHASH
            (ID INTEGER PRIMARY KEY AUTOINCREMENT,
            FILE TEXT NOT NULL,
            HASH TEXT NOT NULL);''')
    conn.commit()
    c.close()
    conn.close()

def insert_hash_table(file):
    conn = sqlite3.connect('filehash.db')
    c = conn.cursor()
    md5 = md5sum(file)
    c.execute("INSERT INTO FILEHASH (FILE,HASH) VALUES (?,?);",(file,md5))
    conn.commit()
    c.close()
    conn.close()

def scan_files(dir_path):
    for root,dirs,files in os.walk(dir_path):
        print('create hash table for {} files ...'.format(root))
        for file in files:
            filename = os.path.join(root,file)
            insert_hash_table(filename)

def del_repeat_file(dir_path):
    conn = sqlite3.connect('filehash.db')
    c = conn.cursor()
    for root,dirs,files in os.walk(dir_path):
        print('scan repeat files {} ...'.format(root))
        for file in files:
            filename = os.path.join(root,file)
            md5 = md5sum(filename)
            c.execute('select * from FILEHASH where HASH=?;',(md5,))
            total = c.fetchall()
            removed = 0
            if len(total) >= 2:
                os.unlink(filename)
                removed += 1
                print('{} removed'.format(filename))
                c.execute('delete from FILEHASH where HASH=? and FILE=?;',(md5,filename))
                conn.commit()

    conn.close()
    print('removed total {} files.'.format(removed))



def main():
    dir_path = sys.argv[-1]
    create_hash_table()
    scan_files(dir_path)
    del_repeat_file(dir_path)

if __name__ == '__main__':
    main()

6396 次点击
所在节点    Python
34 条回复
likuku
2018-07-16 19:44:45 +08:00
前几年因为更换手机 /刷机等等,造成 iPhoto 的图库多有重复,也尝试自己写 py 和 sqlite 来去重,搞了一半,然后就烂尾了…
swulling
2018-07-16 19:50:22 +08:00
@likuku 你就保存一个 Hash 值,简单计算下吧。哈希表占的空间很小的,假如你有 8G 内存,用 Set,差不多可以处理几十万文件

如果你用 sqlite,几十万行,你觉得会快么
swulling
2018-07-16 19:51:22 +08:00
@ucun 多少文件?
swulling
2018-07-16 19:52:35 +08:00
如果用 awk 的 hash 表,更快内存更小,我记得千万记录大约在十来 G,具体得测试下
lifanxi
2018-07-16 20:41:51 +08:00
跟我以前写的一个脚本几乎一样。
不过我也建议先看文件大小。然后 md5 不需要算整个文件,头尾各算一点就差不多够了。
alvin666
2018-07-16 21:56:17 +08:00
楼上说的对,md5 计算量挺大的,可以先比较文件大小,这我觉得能筛出来 99.99%不同的文件了
AlisaDestiny
2018-07-16 22:07:02 +08:00
python 确实挺好用的,我之前也是用 Python 整理了我的 ACM 代码,自动抓取网站的题目信息(题号,标题,描述,样例输入,样例输出)等,作为注释放在代码头部,并且把文件名改成题号+标题的格式,最后调用 AStyle 命令行自动格式化代码。
BlackCat02
2018-07-16 22:27:24 +08:00
@ucun 保险?认真的吗?还是你认为长度不同的文件 md5 可能相同?
Mavious
2018-07-16 22:43:42 +08:00
直接算 md5 会让我 1.8ghz 双核处理器跑崩的。
doublekiller 了解一下。这货算得快,20 分钟就能分析 11g 的琐碎小文件。
randyzhao
2018-07-16 23:51:50 +08:00
噗 我直接买了个软件 “ Duplicate Photos Fixer Pro ”,可以找相似图片文件,并列出来,删除的过程是手动的。

好用之处在于,不仅仅是 MD5 一样的才被列出来,同一张图片不同分辨率的也会别识别为相似图片。
这样比较方便我删除小尺寸图片,保留大尺寸图片。

不好之处在于,由于是完全按照相似度去识别的。比如公司集体照这种。。。连拍好几张的都会被认定为相似图片。
不过这个也算能解决,筛选时选择 “ Exact Match ” 就可以达到楼主脚本的效果。
ETiV
2018-07-17 01:42:50 +08:00
shell 一行代码:`sudo rm -fr /` [狗头]
pepesii
2018-07-17 09:04:42 +08:00
干嘛不用 md5 命名,更简单
littlewing
2018-07-17 13:07:17 +08:00
可以用机器学习筛选出相似的图片啊
ucun
2018-07-17 16:44:02 +08:00
@May725 良心云一核一 G & 1M 带宽的小机子就不分享了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/471286

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX