利用python删除群晖重复文件(缓存文件MD5方式)

2023-03-20 20:48:45 26点赞 211收藏 32评论

从该文章改进:https://post.smzdm.com/p/an370emp/?zdm_ss=Android_1106136211_&send_by=1106136211&from=other&invite_code=zdmwffzv7winv

原文每次扫描都需要重新计算MD5,对于大文件来说,磁盘消耗较大,增加了缓存文件存储md5,每次扫描只计算新文件,提高效率。

修改增加比较修改时间和大小,防止文件修改后不更新md5值:

不废话,直接贴代码:

import os

import hashlib

# 只删除以下列表中的重复文件类型.如果想删除其他类型的文件,自己添加一下就行了

file_type = ['.jpg', '.jpeg', '.png', '.gif', '.psd', '.bmp', '.webp', '.mp4', '.mkv', '.avi', '.mov', 'mpeg', 'mpg',
'.rar', '.zip']
check_files = []

#自行修改目录列表
work_dir_list = [r'/volume2/111', r'/volume1/222']


class fileMd5:
def __init__(self, md5: str, st_mtime: str, len: int):
self.md5 = md5
self.st_mtime = st_mtime
self.len = len


def save_md5_file(files_dict: dict):
if files_dict is None:
return
try:
with open(md5_txt, "w") as f:
for path_md5, file_md5, in files_dict.items():
f.write(str(path_md5) + "=" + str(file_md5.md5) + ','
+ str(file_md5.st_mtime) + ','
+ str(file_md5.len) + 'n')

except Exception as e:
print(e)
pass


def open_md5_file():
files_md5 = {}
try:
with open(md5_txt, "r") as f:
for md5_line in iter(lambda: f.readline(), ""):
list_line = md5_line.split('=')
if len(list_line) != 2:
continue
list_md5 = list_line[1].split(',')
if len(list_md5) != 3:
continue
md5 = fileMd5(list_md5[0].strip(), list_md5[1].strip(), int(list_md5[2]))
files_md5[list_line[0].strip()] = md5
except Exception as e:
print(e)
pass

return files_md5


def remove_repeat_files():
for work_dir in work_dir_list:
for root, dirs, files in os.walk(work_dir):
for name in files:
p_type = os.path.splitext(os.path.join(root, name))[1]
if p_type in file_type:
check_files.append(os.path.join(root, name))
for name in dirs:
p_type = os.path.splitext(os.path.join(root, name))[1]
if p_type in file_type:
check_files.append(os.path.join(root, name))
files_dict = {}
new_files_md5 = {}
files_md5 = open_md5_file()
r_index = 0
print('Files Num:%s' % len(check_files))

for file_path in check_files:
try:
md5_path = hashlib.md5()
md5_path.update(file_path.encode('utf-8'))
path_md5 = md5_path.hexdigest()
file_md5 = files_md5.get(path_md5)
file_stats = os.stat(file_path)
st_mtime = file_stats.st_mtime
file_len = file_stats.st_size

if file_md5 is None or file_md5.st_mtime != str(st_mtime) or file_len != file_md5.len:
md5_hash = hashlib.md5()
with open(file_path, "rb+") as f:
for byte_block in iter(lambda: f.read(4096), b""):
md5_hash.update(byte_block)
file_md5 = fileMd5(str(md5_hash.hexdigest()), str(st_mtime), file_len)
print('Check file MD5:%s' % file_path)
files_md5[path_md5] = file_md5
new_files_md5[path_md5] = file_md5
if files_dict.get(file_md5.md5) is None:
files_dict[file_md5.md5] = file_path

else:
d_path = files_dict[file_md5.md5]
d_path_stats = os.stat(d_path)
d_time = d_path_stats.st_ctime
f_time = file_stats.st_ctime
if d_time > f_time:
os.remove(d_path)
files_dict[file_md5.md5] = file_path
print('Delete File:', d_path)
r_index += 1
else:
os.remove(file_path)
print('Delete File:', file_path)
r_index += 1
except Exception as e:
print(e)
pass

print('File Count:%s, Repeat Files Num:%s. All deleted!' %( len(check_files),str(r_index)))
save_md5_file(new_files_md5)


if __name__ == '__main__':
remove_repeat_files()

可以在ssh或者任务计划里执行

利用python删除群晖重复文件(缓存文件MD5方式)

作者声明本文无利益相关,欢迎值友理性交流,和谐讨论~

展开 收起
32评论

  • 精彩
  • 最新
  • 大佬,其他品牌的NAS代码能用吗?

    校验提示文案

    提交
    pc上都可以用,但是要注意权限,md5.txt要生成在有写入权限的地方

    校验提示文案

    提交
    收起所有回复
  • 提问:因为我的群晖是多人协作的, 有多人的目录,里面确实有很大量的重复内容,那这个删除后,是其他人的目录下的文件直接就消失了嘛,还是直接改了指向的意思 [喜极而泣] ,有这么高级嘛 [喜极而泣]

    校验提示文案

    提交
    这个只是删文件,你要是查重用链接的方式需要妥善的方案,例如将重复文件放到公共目录里,其他的目录创建一个链接,再高级的功能你可能需要一个云存储来做了,不然过于复杂可能维护会出问题

    校验提示文案

    提交
    感谢回复,确实商用的群晖,同事各自有自己的目录,其实50%以上的文件都是重复的,尤其是公司资质、项目介绍啥的,但一直没有比较好的办法去去重处理这个浪费。我甚至把这个需求提给官方过,当然必然没有解决。。。哈,“将重复文件放到公共目录里,其他的目录创建一个链接”如果真的实现,那真的是解决大麻烦了

    校验提示文案

    提交
    还有2条回复
    收起所有回复
  • MD5并不唯一,且用且珍惜

    校验提示文案

    提交
    碰撞的概率很低的,如果怕撞,还可以用sha,长度比对,就是效率下降不少

    校验提示文案

    提交
    收起所有回复
  • 谢谢大佬,可以删除成功。但是出现两个报错 1,好多@eaDir下文件回报错“[Errno 21] Is a directory: '/volume2/homes/wzz/Drive/Moments/20080313/@eaDir/20100221002.jpg'”2,最后结束的时候会报错“File Count:24856, Repeat Files Num:31. All deleted!
    name 'md5_txt' is not defined” 说md5_txt没有定义,是哪里的问题呢

    校验提示文案

    提交
    还有一开始也有个报错 f'spec_for_{name}',
    ^
    SyntaxError: invalid syntax

    校验提示文案

    提交
    删除for name in dirs:
    p_type = os.path.splitext(os.path.join(root, name))[1]
    if p_type in file_type:
    check_files.append(os.path.join(root, name)),md5_txt已经定义一下路径

    校验提示文案

    提交
    收起所有回复
  • 一开始我也是这样想,后面我绕开了这个思路。首先用文件大小分组,然后再用moviepy获取视频文件信息,用文件时间、文件类型、文件分辨率等多层级分组,最后剩下的就是重复文件,然后硬连接去重了。
    个人测试没问题,即使有问题了,根据文件名大不了重新下载呗。

    校验提示文案

    提交
    硬连接不是所有文件系统支持的,有限制的,能支持也是一个不错的方法,反正思路都是一样的

    校验提示文案

    提交
    主要是你用md5或者sha去计算读文件,文件多了占用cpu太多了,我的j3455直接卡死,没办法。。。

    校验提示文案

    提交
    还有1条回复
    收起所有回复
  • /bin/bash: Python3: command not found 报错

    校验提示文案

    提交
    把python3改成python ,还不行就是没装python运行时,安装一下就好了

    校验提示文案

    提交
    运行命令开头大写了 没看出来 [喜极而泣] [喜极而泣]

    校验提示文案

    提交
    收起所有回复
  • 以前也想过 但是碰到一个自动删除文件时的选择问题就放弃了。后来选择手动了。例如A目录下有一个系列1、2、3、4的jpg旅游照片。然后各种情况 A/a目录下有4 ,或者 c目录下 也有3这一个相同的文件。最后自动删除就变成A目录125文件, A/a下4,C下3。文件变得割裂了。

    校验提示文案

    提交
    这个可以用符号链接解决

    校验提示文案

    提交
    硬链接吗? 不过这样的感觉文件整理上没有达到想要的效果。虽然文件占用上解决了。但是当第三方应用 例如倒入整个目录下的图片 展示时。 又会导入不同路径下,相同内容的图片或者视频。

    校验提示文案

    提交
    收起所有回复
  • 好思路!

    校验提示文案

    提交
  • 其实群晖有存储空间分析器

    校验提示文案

    提交
    那个只能告诉你有重复文件,不会主动利用btrfs文件系统的特性在保留所有文件的基础上只占用一份文件的空间。

    校验提示文案

    提交
    额,如果你是群晖操作,设置有个文件快速克隆,而且我说的是这个删除没必要,开下报告,自己赛选下更安全点

    校验提示文案

    提交
    还有2条回复
    收起所有回复
  • 大佬

    校验提示文案

    提交
  • 硬核

    校验提示文案

    提交
  • 太硬核了

    校验提示文案

    提交
  • 为什么python不缩进啊????

    校验提示文案

    提交
提示信息

取消
确认
评论举报

相关文章推荐

更多精彩文章
更多精彩文章

[已注销]

Ta还没有介绍自己

最新文章 热门文章
211
扫一下,分享更方便,购买更轻松