利用MT Photos生成的重复文件列表,删除重复文件

本文介绍了如何使用Python脚本来查找并处理NAS系统上的重复图片,特别是针对MTPhotosDocker应用。首先,通过MTPhotos获取重复文件信息并保存,然后运行Python脚本将信息转存到Excel表格,最后生成Shell脚本进行批量删除。这种方法对于大量重复图片的管理非常有效。
Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

除了群晖,其他NAS系统的相册应用实在是难以忍受。所以发现了MT Photos,这是在NAS里面一个非常好用的docker相册应用。
但是我们从网上下了大量的图片过后,也会有很多很多重复的图片。
这里说的重复图片,是指大小、尺寸等一摸一样的文件。
如果重复的图片有成千上万张,那么手动删起来是非常有损手腕健康的。
所以写了这个python脚本,用于生成批量删除的shell脚本。


提示:以下是本篇文章正文内容,下面案例可供参考

一、获取重复文件信息

在这里插入图片描述
步骤:
1、到MTPhotos的重复文件查找界面,按F12打开前端调试;
2、再按F5刷新界面,已重新获取重复文件信息:findDuplicateFiles;
3、按照图中这样,将findDuplicateFiles信息保存到文件"MTphotos重复文件.txt"中。
注意:这里要求固定文件名是"MTphotos重复文件.txt"

二、使用步骤

1. 运行“MTphotos重复文件(生成excel).py”

在这里插入图片描述

代码如下:

import platform
import os
import re
import pandas as pd

OS = platform.system()

file=open('MTphotos重复文件.txt', 'r',encoding='UTF-8')

same_file = {}

file_info_list = []
line_num = 1

def save_filelist_to_excel(data,excelname):
    sheetname1 = '重复列表'
    sheetname2 = 'Volume映射'

    form_header =['主']
    for i in range(in_group_same_max):
        if i>=1:
            form_header.append('删%d'%i)
    pf1 = pd.DataFrame(columns=form_header)

    x = 0
    for md5 in data:
        n=len(data[md5])
        n = in_group_same_max - n
        for i in range(n):  #要求与标题数量匹配,所以不够的补一下
            data[md5].append('')
        pf1.loc[x] = data[md5]
        x=x+1
    
    #填入docker中的volume映射设置,以便生成shell时,自动替换虚拟路径
    pathmap = \
    [ \
        ['/upload/',       '/volume1/Public/散图/'],                                      \
        ['/COSPLAY/',      '/share/MyArchive1/PRIVATE/PHOTO/[COSPLAY]/'],                 \
        ['/XiuRen秀人网/', '/share/MyArchive1/PRIVATE/PHOTO/[XiuRen秀人网]/'],            \
        ['/非成套/',       '/share/MyArchive1/PRIVATE/PHOTO/[非成套]/'],                  \
        ['/港台日韩/',     '/share/MyArchive1/PRIVATE/PHOTO/[港台日韩]/'],                \
        ['/套图/',         '/share/MyArchive1/PRIVATE/PHOTO/[套图]/']                     \
    ]
    
    form_header =['虚拟目录', '实际路径']
    pf2 = pd.DataFrame(columns=form_header)
    x = 0
    for Volume in pathmap:
        pf2.loc[x] = Volume
        x = x+1

    with pd.ExcelWriter(excelname) as writer:
        pf1.to_excel(writer, sheet_name=sheetname1, index=False)
        pf2.to_excel(writer, sheet_name=sheetname2, index=False)
    return 1
        
    
def sort_path_filename(data):
    num = len(data)
    group = []
    for fullpath in data:
        (filepath, filename) = os.path.split(fullpath)  ##分离文件路径与文件名
        (name, suffix) = os.path.splitext(filename) #分离文件名和扩展名
        group.append([filepath,name,suffix])
    
    #如果是一个目录下的,就判断文件名
    #因为"file (1).jpg"和"file.jpg"判断结果是,"file (1).jpg"是小的
    #而我觉得"file.jpg"才是小的,所以判一下文件名
    group.sort()
    for i in range(num):
        if OS == 'Windows':     #在windows下生成linux的路几个
            data[i] = (group[i][0] + '/' + group[i][1] + group[i][2])
        else:
            data[i] = os.path.join(group[i][0], group[i][1] + group[i][2])    
    return 1

for line in file:
    string = line.strip()
    str_pat = re.compile(r'\"(.*?)\"')  #正则表达式,取两个双引号之间的字符串 part1
        
    if string == '{':
        pass
    if "\"id\"" in string:
        splitext = string.split(':')
        ID = re.sub(r'[^0-9]', '', splitext[1]) #正则表达式,取全部的数字
    if "\"path\"" in string:
        splitext = string.split(':')
        PATH = str_pat.findall(splitext[1])[0] #正则表达式,取两个双引号之间的字符串 part2
    if "\"md5\"" in string:
        splitext = string.split(':')
        MD5  = str_pat.findall(splitext[1])[0]
    if "\"size\"" in string:
        splitext = string.split(':')
        SIZE = str_pat.findall(splitext[1])[0]
        SIZE = int(SIZE,10)
    if string == '},' or string == '}':
        same_file.setdefault(MD5,[]).append(PATH)
    line_num = line_num + 1
file.close()

num = len(same_file)
print(num)
in_group_same_max=2 #每组重复文件的最大个数
n=0

print('[', end='')
for md5 in same_file:
    l=len(same_file[md5])
    in_group_same_max = max(l,in_group_same_max)
    sort_path_filename(same_file[md5])
    n = n+1
    if n%int(num/10) == 0:
        print('■', end='')
print(']', end='')
print('')

save_filelist_to_excel(same_file,'重复文件列表.xlsx')

在这里插入图片描述

2.运行“2 生成shell脚本(按调整后的excel生成shell).py”

代码如下(示例):

#!/usr/bin/env python3
import pandas as pd
import os
import struct
#import platform
#pip install openpyxl
#pip install pandas

def get_file_list(excel_data):
    del_num = 1
    list_info = []
    for row in excel_data.index.values: #读全部行
        line = excel_data.iloc[row]
        #print(line)
        for column in line:
            if list(line).index(column) != 0 and column != '':
                list_info.append(column)
                del_num = del_num+1
    return list_info

def get_real_path(excel_data, volume):
    if volume in excel_data['虚拟目录'].values:
        path = excel_data.loc[excel_data['虚拟目录'] == volume, ['实际路径']].values[0][0]
        #print(path)
        return path
    else:
        print('没找到\"%s\"'%volume)
        return ''

def path_replace(mtphoto_out_path):
    mtphoto_out_path = '/'+file.split('/')[1]+'/'
    path = get_real_path(df22, mtphoto_out_path)
    if(path != ''):
        return file.replace(mtphoto_out_path, path, 1)
    else:
        return mtphoto_out_path

#OS = platform.system()
CurrPath = os.getcwd()

#读取工作簿和工作簿中的工作表
FileName = "重复文件列表.xlsx"
sheetname1 = '重复列表'
sheetname2 = 'Volume映射'
FilePath = os.path.join(CurrPath, FileName)

pd.set_option('display.unicode.east_asian_width', True)
#df=pd.read_excel(FilePath) #默认第一个
df11=pd.read_excel(FilePath, sheet_name='重复列表',keep_default_na=False)
df22=pd.read_excel(FilePath, sheet_name='Volume映射',keep_default_na=False)
#print(df.head())    #打印前5行

#因为是给linux用,不能有windows的\r换行
#所以采用二进制写入
saveshell = open('same_photo.sh', 'wb')
file_list = get_file_list(df11)
for file in file_list:
    new_path = path_replace(file)
    cmd = 'rm -f \"%s\"\n'%new_path
    #cmd = cmd.encode('utf-8')
    cmd = bytes(cmd, encoding='UTF-8')
    saveshell.write(cmd)
saveshell.close()
file_list.clear()

最终输出文件

在这里插入图片描述


总结

本文使用了pandas,对excel进行了简单的处理。

您可能感兴趣的与本文相关的镜像

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

MT4开发中,防止头文件和库文件的重复包含是确保代码结构清晰和避免编译错误的重要步骤。虽然MT4使用的MQL4语言没有像C/C++那样直接支持`#ifndef`、`#define`、`#endif`等预处理指令来防止头文件重复包含,但可以通过以下方法有效地避免重复包含问题。 ### 使用条件包含逻辑 MQL4支持基本的预处理指令,可以通过`#import`和`#include`控制文件的导入。虽然无法完全模拟C/C++的“include guard”,但可以采用一种逻辑上的“标志变量”机制来模拟类似效果。 在头文件顶部定义一个全局变量作为“标志”,用于指示该文件是否已经被包含。例如: ```mql4 // myheader.mqh #ifndef MYHEADER_INCLUDED #define MYHEADER_INCLUDED // 头文件内容 #endif ``` 然而,MQL4并不直接支持上述语法,因此需要通过脚本逻辑实现类似的机制。例如,在自定义头文件的顶部添加一个全局变量作为标记: ```mql4 // myheader.mqh if (!IsDefined("MYHEADER_INCLUDED")) { #define MYHEADER_INCLUDED // 头文件的实际内容 } ``` ### 合理组织文件结构 确保每个头文件只被包含一次,并在项目中统一管理包含路径。在开发过程中,应明确每个头文件的用途,并在主脚本或EA中只引用一次,避免多个模块重复引用同一头文件。 ### 使用库文件替代头文件 对于重复使用的函数和逻辑,推荐将其实现为库文件(`.ex4`),而不是头文件(`.mqh`)。库文件在编译后以二进制形式存在,不会出现重复包含的问题。使用`#import`导入库函数时,只需指定一次即可。 例如: ```mql4 #import "MyLibrary.ex4" int MyFunction(int param); #import ``` ### 避免嵌套包含 尽量避免在头文件中再包含其他头文件。如果必须嵌套包含,应确保每个头文件都采用了上述的“标志变量”机制,或者通过库文件替代,以减少依赖关系。 ### 使用MQL4的`#include_once`机制(模拟) 虽然MQL4没有内置的`#include_once`指令,但可以通过外部脚本或构建工具在编译前检查并自动排除重复的`#include`语句。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值