删除微信重复文件的简易工具

去我的个人博客观看,观感更佳哦,😙😙

前言

!!!!温馨提示:假如你是小白,啥都不懂,请直接跳到文章的最后!!!

原本我是没想写这篇文章,契机是某一天我突然打开微信的存储空间占用才发现。多少?😡我寻思平常也不怎么用微信,怎么占用的空间这么离谱,居然有20个G左右,这是在微信上存了个小电影吗?

在这里插入图片描述

抱着好奇心的我,打开了微信的物理存储位置,其他平台我没试过,仅在windows平台下测试过,存储位置一般能通过这样打开

在这里插入图片描述

找寻到存储文件的位置,一般是子目录 FileStorage\File这个位置就是用来存储通过微信保存的各种文件,而且会按照日期排序

在这里插入图片描述

随便点进去一个会发现,这个文件夹下存储了大量相同的文件,然后在原有的文件的名字后面加上(1),(2),(3),(1)(1)这种序号,也就是说这些文件都是被重复存储了

在这里插入图片描述

存在的问题

通过上面的流程,可以得出一个结论,微信是存储了大量重复文件,才会占用这么大的存储空间,我在网上也找了一些解释,这个似乎跟微信的存储策略有关

据悉,这种情况出现的原因之一是微信的文件转发策略导致。例如将同一份文件转发给多个好友,每一次转发都会重新保存一份在手机上,重复文件占用了手机大量存储空间。而且过大的空间占用也会使手机出现明显的卡顿和发热等情况,影响正常使用。

也就是说,我们完全可以把这些重复的文件全部删除,但是我的微信记录已经有好几年了,要是一个个删除,是一件费时费力的方法。于是!🤓我突发奇想,既然这样的话,编写一个批量删除的程序不就行了?😗

效果展示

老规矩,我喜欢在看一系列繁琐的步骤前先看看效果,这样我才有继续看下去的欲望,相信大多数人都是这样想的😝

  1. 首先执行程序,选择是否要进行递归删除,递归删除意思就是,你选择的目录的子目录里面的重复文件也会被删除。这里我们选择n

    在这里插入图片描述

  2. 选择路径

  3. 执行效果,按回车可以退出

在这里插入图片描述

  1. 删除的文件会到回收站里面,而不是永久删除,这样就能有撤销的余地了

问题的解决与思路

这块的内容会涉及到一些专业知识,假如你不懂,那么直接跳过就行,使用我打包好的程序即可。

  1. 首先通过观察可以发现,微信在保存这些重复文件的特点是在文件名后加上序号,比如
字符串.doc
字符串(1).doc
字符串(2).doc
字符串(1)(1).doc

我们可以通过正则表达式去匹配这种字符串,“字符”+“序号”.”后缀名”

"""
.*表示匹配任意字符
(\d)匹配带有括号的序号
"""
.*\(\d\).*

这样我们就能通过程序识别这些文件

  1. 其他,有次非常关键的点是,假如你在微信勾选了这个选项,那么存储的文件会因为只读权限,导致删除失败,因此在识别到文件之后,我们还需要改变文件的权限,才能删除,这里可以使用os.chmod函数做到
    在这里插入图片描述
#权限检查,移除只读属性
    for file in matchfilelist:
        try:
            os.chmod(file, stat.S_IWRITE)
            send2trash.send2trash(os.path.normpath(file))#将匹配的文件放入回收站
            print(f"成功删除了文件: {file}")
        except Exception as e:
            print(f"删除文件时出现错误: {file},错误信息: {e}")
  1. 最后我们需要解决的问题是,由于文件夹的子目录数量非常多,因此我们可能不想对每个文件夹都单独执行一遍程序,最好是能递归地自动执行,这里我们可以使用os.walk,它可以记录目录的文件数,从而能递归对子目录也进行删除操作
def recursive_delete_file(directory):
    for root, dirs, files in os.walk(directory):
        delete_file(root)

完整程序实现

import os
import stat
import re
import tkinter as tk
from tkinter import filedialog
import send2trash
def delete_file(folder_path):
    pattern = re.compile(r'.*\(\d\).*')
    filelist=os.listdir(folder_path)
    matchfilelist=[]
    #找出匹配的文件名
    for file in filelist:
        if re.match(pattern,file):
            matchfilelist.append(folder_path+"/"+file)
    #权限检查,移除只读属性
    for file in matchfilelist:
        try:
            os.chmod(file, stat.S_IWRITE)
            send2trash.send2trash(os.path.normpath(file))#将匹配的文件放入回收站
            print(f"成功删除了文件: {file}")
        except Exception as e:
            print(f"删除文件时出现错误: {file},错误信息: {e}")

def recursive_delete_file(directory):
    for root, dirs, files in os.walk(directory):
        delete_file(root)

def main():
    root = tk.Tk()
    root.withdraw()  # 隐藏主窗口
    print("是否采取递归删除?(y/n),递归操作相当危险,请谨慎选择")
    flag=input()
    file_path = filedialog.askdirectory() # 打开文件选择对话框
    if flag=="y" or flag=='Y':
        recursive_delete_file(file_path)
    else:
        delete_file(file_path)
    root.destroy()
    input("按回车键退出")
if __name__=='__main__':
    main()

2024-10-10更新

最近我正在学习pyqt,因此🤓!!我用qt框架将原来的代码封装了一下,做了一个简单的界面(学以致用嘛😗)

代码

import os
import stat
import re
from sys import argv
from sys import exit
import send2trash
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
from PyQt5 import QtCore, QtWidgets
class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName("文件删除工具")
        Form.resize(383, 182)
        self.verticalLayoutWidget = QtWidgets.QWidget(Form)
        self.verticalLayoutWidget.setGeometry(QtCore.QRect(0, 0, 381, 181))
        self.verticalLayoutWidget.setObjectName("verticalLayoutWidget")
        self.verticalLayout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget)
        self.verticalLayout.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout.setObjectName("verticalLayout")
        self.textBrowser = QtWidgets.QTextBrowser(self.verticalLayoutWidget)
        self.textBrowser.setObjectName("textBrowser")
        self.verticalLayout.addWidget(self.textBrowser, 0, QtCore.Qt.AlignVCenter)
        self.horizontalLayout = QtWidgets.QHBoxLayout()
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.pushButton = QtWidgets.QPushButton(self.verticalLayoutWidget)
        self.pushButton.setObjectName("pushButton")
        self.horizontalLayout.addWidget(self.pushButton)
        self.pushButton_2 = QtWidgets.QPushButton(self.verticalLayoutWidget)
        self.pushButton_2.setObjectName("pushButton_2")
        self.horizontalLayout.addWidget(self.pushButton_2)
        self.verticalLayout.addLayout(self.horizontalLayout)

        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", "Form"))
        self.textBrowser.setHtml(_translate("Form", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
"p, li { white-space: pre-wrap; }\n"
"</style></head><body style=\" font-family:\'SimSun\'; font-size:9pt; font-weight:400; font-style:normal;\">\n"
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'Ubuntu Mono derivative Powerline\',\'Consolas\',\'Courier New\',\'monospace\'; font-size:16pt; color:#0a3069;\">是否采取递归删除?</span></p>\n"
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:24px; background-color:#ffffff;\"><span style=\" font-family:\'Ubuntu Mono derivative Powerline\',\'Consolas\',\'Courier New\',\'monospace\'; font-size:16pt; color:#0a3069;\">注:递归删除的意思是,将文件子目录的文件也会一并删除</span></p>\n"
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:24px; background-color:#ffffff;\"><span style=\" font-family:\'Ubuntu Mono derivative Powerline\',\'Consolas\',\'Courier New\',\'monospace\'; font-size:16pt; color:#0a3069;\">请谨慎使用!!!</span></p></body></html>"))
        self.pushButton.setText(_translate("Form", "是"))
        self.pushButton_2.setText(_translate("Form", "否"))

def delete_file(folder_path):
    pattern = re.compile(r'.*\(\d\).*')
    filelist=os.listdir(folder_path)
    matchfilelist=[]
    #找出匹配的文件名
    for file in filelist:
        if re.match(pattern,file):
            matchfilelist.append(folder_path+"/"+file)
    #权限检查,移除只读属性
    for file in matchfilelist:
        try:
            os.chmod(file, stat.S_IWRITE)
            send2trash.send2trash(os.path.normpath(file))#将匹配的文件放入回收站
            print(f"成功删除了文件: {file}")
        except Exception as e:
            print(f"删除文件时出现错误: {file},错误信息: {e}")

def recursive_delete_file(directory):
    for root, dirs, files in os.walk(directory):
        delete_file(root)
class delete_tool_widget(QWidget,Ui_Form):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("文件删除工具")
        self.setupUi(self)
        self.pushButton.clicked.connect(self.yes_event)
        self.pushButton_2.clicked.connect(self.no_event)
    def yes_event(self):
        directory = QFileDialog.getExistingDirectory(None,"选择目录",".",QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks)
        recursive_delete_file(directory)
        exit(app.exec_())
    def no_event(self):
        directory = QFileDialog.getExistingDirectory(None,"选择目录",".",QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks)
        delete_file(directory)
        exit(app.exec_())
   
if __name__=='__main__':
    app=QApplication(argv)
    window=delete_tool_widget()
    window.show()
    exit(app.exec_())
    input()
    

界面

在这里插入图片描述

给小白

假如上面的内容你完全不知道是什么,不会python,也不知道啥是脚本。没事,没事🫠,直接下载我打包好的exe程序就行了😈

初版程序:https://github.com/kashima19960/Wechat_Duplicatefiles_Delete/releases/download/v1/main.exe

2024-10-10更新的程序:https://github.com/kashima19960/Wechat_Duplicatefiles_Delete/releases/download/v2/main.exe

免责声明

本程序旨在帮助用户删除特定模式的文件。使用本程序可能会导致数据丢失,包括重要文件。请在使用前确保您已充分了解本程序的功能,并已做好数据备份。 作者不对使用本程序造成的任何直接或间接损失负责,包括但不限于数据丢失、硬件损坏或业务中断。使用本程序即表示您同意自行承担所有风险。 请在使用前仔细阅读并理解本程序的使用说明。如果您不同意本免责声明的任何部分,请不要使用本程序。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值