当前位置: 首页 > article >正文

Python项目73:自动化文件备份系统1.0(tkinter)

主要功能说明:
1.界面组件:源文件夹和目标文件夹选择(带浏览按钮),备份间隔时间设置(分钟),立即备份按钮,自动备份切换按钮,状态栏显示备份状态。
2.进度条显示:使用ttk.Progressbar实现精确进度显示,根据实际文件数量更新进度,实时显示已复制文件数量。
3.文件过滤功能:包含:*.docx, *.xlsx,排除:temp, ~$,支持包含/排除模式(支持通配符)。
4.日志记录系统:自动生成backup_log.txt,记录每次备份的详细信息,支持查看日志窗口(带滚动条)。
5.增量备份选项:通过MD5哈希比较文件内容,仅复制修改过的文件,可切换完整/增量备份模式。

6.使用说明:设置源目录和目标目录,配置过滤规则(可选),选择备份模式(完整/增量),设置自动备份间隔,通过按钮执行立即备份或自动备份,可随时查看备份日志。使用独立线程进行自动备份,避免界面卡顿,自动生成带时间戳的备份目录,实时状态反馈,错误处理机制。

7.注意事项:需要确保目标驱动器有足够空间,长时间运行的自动备份建议在后台运行,第一次使用时建议先进行手动备份测试,增量备份基于文件内容比对,大文件可能会影响性能,过滤规则支持标准shell通配符语法,日志文件保存在程序运行目录,进度条精度取决于文件数量而非大小。
在这里插入图片描述


# -*- coding: utf-8 -*-
# @Author : 小红牛
# 微信公众号:WdPython
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
import shutil
import os
from datetime import datetime
import threading
import time
import fnmatch
import hashlibclass BackupApp:def __init__(self, root):self.root = rootself.root.title("高级自动备份工具")self.root.geometry("650x450")# 初始化变量self.is_auto_backup_running = Falseself.total_files = 0self.copied_files = 0self.backup_mode = tk.StringVar(value="full")  # 备份模式# 创建界面组件self.create_widgets()self.setup_logging()def setup_logging(self):"""初始化日志系统"""self.log_path = os.path.join(os.getcwd(), "backup_log.txt")if not os.path.exists(self.log_path):with open(self.log_path, "w") as f:f.write("备份日志记录\n\n")def create_widgets(self):# 创建主容器main_frame = ttk.Frame(self.root)main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)# 源文件夹选择source_frame = ttk.LabelFrame(main_frame, text="源目录设置")source_frame.grid(row=0, column=0, columnspan=3, sticky="we", pady=5)self.source_entry = ttk.Entry(source_frame, width=50)self.source_entry.grid(row=0, column=0, padx=5, pady=5)ttk.Button(source_frame, text="浏览...", command=self.select_source).grid(row=0, column=1, padx=5)# 目标文件夹选择target_frame = ttk.LabelFrame(main_frame, text="目标目录设置")target_frame.grid(row=1, column=0, columnspan=3, sticky="we", pady=5)self.target_entry = ttk.Entry(target_frame, width=50)self.target_entry.grid(row=0, column=0, padx=5, pady=5)ttk.Button(target_frame, text="浏览...", command=self.select_target).grid(row=0, column=1, padx=5)# 过滤设置filter_frame = ttk.LabelFrame(main_frame, text="文件过滤设置")filter_frame.grid(row=2, column=0, sticky="we", pady=5, padx=5)ttk.Label(filter_frame, text="包含模式(逗号分隔):").grid(row=0, column=0)self.include_pattern = ttk.Entry(filter_frame)self.include_pattern.grid(row=0, column=1, padx=5)ttk.Label(filter_frame, text="排除模式(逗号分隔):").grid(row=1, column=0)self.exclude_pattern = ttk.Entry(filter_frame)self.exclude_pattern.grid(row=1, column=1, padx=5)# 备份设置setting_frame = ttk.LabelFrame(main_frame, text="备份设置")setting_frame.grid(row=2, column=1, sticky="we", pady=5, padx=5)ttk.Label(setting_frame, text="间隔(分钟):").grid(row=0, column=0)self.interval_entry = ttk.Entry(setting_frame, width=8)self.interval_entry.grid(row=0, column=1, padx=5)self.interval_entry.insert(0, "60")ttk.Radiobutton(setting_frame, text="完整备份", variable=self.backup_mode, value="full").grid(row=1, column=0)ttk.Radiobutton(setting_frame, text="增量备份", variable=self.backup_mode, value="incremental").grid(row=1,column=1)# 进度条self.progress = ttk.Progressbar(main_frame, orient=tk.HORIZONTAL, mode='determinate')self.progress.grid(row=3, column=0, columnspan=3, sticky="we", pady=10)# 按钮区域btn_frame = ttk.Frame(main_frame)btn_frame.grid(row=4, column=0, columnspan=3, pady=10)ttk.Button(btn_frame, text="立即备份", command=self.manual_backup).pack(side=tk.LEFT, padx=5)self.auto_btn = ttk.Button(btn_frame, text="开始自动备份", command=self.toggle_auto_backup)self.auto_btn.pack(side=tk.LEFT, padx=5)ttk.Button(btn_frame, text="查看日志", command=self.show_logs).pack(side=tk.LEFT, padx=5)# 状态栏self.status_label = ttk.Label(main_frame, text="状态: 就绪", relief=tk.SUNKEN)self.status_label.grid(row=5, column=0, columnspan=3, sticky="we")def select_source(self):path = filedialog.askdirectory()if path:self.source_entry.delete(0, tk.END)self.source_entry.insert(0, path)def select_target(self):path = filedialog.askdirectory()if path:self.target_entry.delete(0, tk.END)self.target_entry.insert(0, path)def manual_backup(self):threading.Thread(target=self.perform_backup, daemon=True).start()def should_include(self, file_path):"""文件过滤逻辑"""include = self.include_pattern.get().strip()exclude = self.exclude_pattern.get().strip()filename = os.path.basename(file_path)# 包含规则if include:patterns = [p.strip() for p in include.split(",")]if not any(fnmatch.fnmatch(filename, p) for p in patterns):return False# 排除规则if exclude:patterns = [p.strip() for p in exclude.split(",")]if any(fnmatch.fnmatch(filename, p) for p in patterns):return Falsereturn Truedef get_file_hash(self, file_path):"""计算文件哈希值(用于增量备份)"""hasher = hashlib.md5()with open(file_path, 'rb') as f:while chunk := f.read(8192):hasher.update(chunk)return hasher.hexdigest()def perform_backup(self):"""执行备份的核心方法"""try:source = self.source_entry.get()target = self.target_entry.get()if not source or not target:messagebox.showerror("错误", "请先选择源文件夹和目标文件夹")returntimestamp = datetime.now().strftime("%Y%m%d_%H%M%S")backup_folder = os.path.join(target, f"backup_{timestamp}")os.makedirs(backup_folder, exist_ok=True)# 获取文件列表并过滤all_files = []for root, dirs, files in os.walk(source):for file in files:full_path = os.path.join(root, file)if self.should_include(full_path):all_files.append(full_path)self.total_files = len(all_files)self.copied_files = 0self.progress['maximum'] = self.total_filesself.progress['value'] = 0# 记录日志log_entry = {'timestamp': datetime.now().strftime("%Y-%m-%d %H:%M:%S"),'source': source,'target': backup_folder,'mode': self.backup_mode.get(),'status': 'success','files': 0}# 执行备份for file_path in all_files:if not self.is_auto_backup_running and self.backup_mode.get() == "incremental":break  # 允许取消增量备份rel_path = os.path.relpath(file_path, source)dest_path = os.path.join(backup_folder, rel_path)os.makedirs(os.path.dirname(dest_path), exist_ok=True)# 增量备份检查if self.backup_mode.get() == "incremental":if os.path.exists(dest_path):src_hash = self.get_file_hash(file_path)dst_hash = self.get_file_hash(dest_path)if src_hash == dst_hash:continueshutil.copy2(file_path, dest_path)self.copied_files += 1self.update_progress()log_entry['files'] = self.copied_filesself.log_backup(log_entry)self.update_status(f"备份完成:复制 {self.copied_files}/{self.total_files} 个文件")except Exception as e:self.update_status(f"备份失败:{str(e)}")messagebox.showerror("错误", str(e))log_entry['status'] = 'failed'log_entry['error'] = str(e)self.log_backup(log_entry)def update_progress(self):"""更新进度条"""self.progress['value'] = self.copied_filesself.root.update_idletasks()def log_backup(self, entry):"""记录备份日志"""with open(self.log_path, "a") as f:f.write(f"[{entry['timestamp']}] {entry['mode'].upper()}备份 "f"源目录: {entry['source']}\n目标目录: {entry['target']}\n"f"状态: {entry['status'].upper()} 文件数: {entry['files']}\n")if 'error' in entry:f.write(f"错误信息: {entry['error']}\n")f.write("-" * 50 + "\n")def show_logs(self):"""显示日志窗口"""log_win = tk.Toplevel(self.root)log_win.title("备份日志")text_area = tk.Text(log_win, wrap=tk.WORD, width=80, height=20)scroll = ttk.Scrollbar(log_win, command=text_area.yview)text_area.configure(yscrollcommand=scroll.set)with open(self.log_path, "r") as f:text_area.insert(tk.END, f.read())text_area.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)scroll.pack(side=tk.RIGHT, fill=tk.Y)def toggle_auto_backup(self):if not self.is_auto_backup_running:try:interval = int(self.interval_entry.get()) * 60if interval <= 0:raise ValueErrorexcept ValueError:messagebox.showerror("错误", "请输入有效的正整数分钟数")returnself.is_auto_backup_running = Trueself.auto_btn.config(text="停止自动备份")self.update_status("自动备份已启动...")self.auto_backup_thread = threading.Thread(target=self.auto_backup_loop, args=(interval,), daemon=True)self.auto_backup_thread.start()else:self.is_auto_backup_running = Falseself.auto_btn.config(text="开始自动备份")self.update_status("自动备份已停止")def auto_backup_loop(self, interval):while self.is_auto_backup_running:self.perform_backup()for _ in range(interval):if not self.is_auto_backup_running:returntime.sleep(1)def update_status(self, message):self.status_label.config(text=f"状态: {message}")if __name__ == "__main__":root = tk.Tk()app = BackupApp(root)root.mainloop()

完毕!!感谢您的收看

----------★★跳转到历史博文集合★★----------
我的零基础Python教程,Python入门篇 进阶篇 视频教程 Py安装py项目 Python模块 Python爬虫 Json Xpath 正则表达式 Selenium Etree CssGui程序开发 Tkinter Pyqt5 列表元组字典数据可视化 matplotlib 词云图 Pyecharts 海龟画图 Pandas Bug处理 电脑小知识office自动化办公 编程工具 NumPy Pygame

相关文章:

Python项目73:自动化文件备份系统1.0(tkinter)

主要功能说明&#xff1a; 1.界面组件&#xff1a;源文件夹和目标文件夹选择&#xff08;带浏览按钮&#xff09;&#xff0c;备份间隔时间设置&#xff08;分钟&#xff09;&#xff0c;立即备份按钮&#xff0c;自动备份切换按钮&#xff0c;状态栏显示备份状态。 2.进度条显…...

C++:扫雷游戏

一.扫雷游戏项目设计 1.文件结构设计 首先我们要先定义三个文件 ①test.c //文件中写游戏的测试逻辑 ②game.c //文件中写游戏中函数的实现等 ③game.h //文件中写游戏需要的数据类型和函数声明等 2.扫雷游戏的主体结构 使⽤控制台实现经典的扫雷游戏 •游戏可以通过菜单…...

使用xlwings将excel表中将无规律的文本型数字批量转化成真正的数字

之前我写了一篇文章excel表中将无规律的文本型数字批量转化成真正的数字-CSDN博客 是使用excel自带的操作&#xff0c;相对繁琐。 今天使用xlwings操作&#xff0c;表格如下&#xff08;有真正的数字&#xff0c;也有文本型数字&#xff0c;混在在一起&#xff09;&#xff1…...

文件包含 任意文件读取

文件处理漏洞--文件包含 - wizard骑士 - 博客园 1&#xff0c;什么是文件包含 程序开发人员一般会吧重复使用的函数写道单个文件中&#xff0c;需要使用某个函数时直接调用此文件&#xff0c;无需再次编写&#xff0c;文件调用的过程就是文件包含&#xff0c;所以将包含的文件…...

缓存套餐-01.Spring Cache介绍和常用注解

一.Spring Cache 要使用直接导入坐标即可。 如何选择底层的缓存实现呢&#xff1f;只要导入对应的缓存坐标即可。如果要使用redis作为缓存实现&#xff0c;那么只需要导入redis的maven坐标。 二.常用注解 Cacheable&#xff1a;不光往缓存中写缓存数据&#xff0c;而且会从缓…...

C++类与对象—下:夯实面向对象编程的阶梯

9. 赋值运算符重载 9.1 运算符重载 在 C 里&#xff0c;运算符重载能够让自定义类型的对象像内置类型那样使用运算符&#xff0c;这极大地提升了代码的可读性与可维护性。运算符重载本质上是一种特殊的函数&#xff0c;其函数名是 operator 加上要重载的运算符。 下面是运算…...

MCP认证全解析:从零到微软认证专家

MCP认证全解析&#xff1a;从零到微软认证专家 什么是MCP认证&#xff1f; Microsoft Certified Professional&#xff08;MCP&#xff09;是由微软官方颁发的技术认证&#xff0c;旨在验证IT从业者在微软技术栈&#xff08;如Azure、Windows Server、SQL Server等&#xff0…...

裸辞8年前端的面试笔记——JavaScript篇(一)

裸辞后的第二个月开始准备找工作&#xff0c;今天是第三天目前还没有面试&#xff0c;现在的行情是一言难尽&#xff0c;都在疯狂的压价。 下边是今天复习的个人笔记 一、事件循环 JavaScript 的事件循环&#xff08;Event Loop&#xff09;是其实现异步编程的关键机制。 从…...

TCP 与 UDP报文

** TCP 与 UDP报文** 1. 引言 在网络通信中&#xff0c;TCP&#xff08;传输控制协议&#xff09; 和 UDP&#xff08;用户数据报协议&#xff09; 是两种最核心的传输层协议。它们各自适用于不同的场景&#xff0c;理解其工作原理对开发高性能网络应用至关重要。本文将详细解…...

开上“Python跑的车”——自动驾驶数据可视化的落地之道

开上“Python跑的车”——自动驾驶数据可视化的落地之道 一、自动驾驶离不开“看得见”的智能 在智能汽车时代,自动驾驶已然不是“炫技”标签,而是一场技术实力的全面拉锯战。而在这场战役中,有一个极其关键但常被忽略的领域,叫做: 数据可视化(Data Visualization)。 为…...

Linux中安装mysql8,转载及注意事项

一、先前往官网下载mysql8 下载地址&#xff1a; https://dev.mysql.com/downloads/选择Linux 二、删除Linux中的mysql&#xff08;如果有的话&#xff09;&#xff0c;上传安装包 1、先查看mysql是否存在&#xff0c;命令如下&#xff1a; rpm -qa|grep -i mysql如果使用这…...

可以下载blender/fbx格式模型网站

glbxz.com glbxz.com可以下载blender/fbx格式模型。当然里面有免费的...

SpringBoot的汽车商城后台管理系统源码开发实现

概述 汽车商城后台管理系统专为汽车4S店和经销商设计&#xff0c;提供全面的汽车管理系统解决方案。 主要内容 1. 核心功能模块 系统提供以下主要功能&#xff1a; ​​销售管理​​&#xff1a;记录销售信息&#xff0c;跟踪交易进度​​客户管理​​&#xff1a;维护客户…...

从入门到深入:Vue.js 学习全攻略

一、Vue.js 入门基础 &#xff08;一&#xff09;Vue.js 简介与环境搭建 Vue.js 是一套用于构建用户界面的渐进式 JavaScript 框架&#xff0c;所谓渐进式&#xff0c;意味着开发者可以根据项目需求&#xff0c;灵活地选择使用 Vue 的功能。它既可以嵌入到简单的 HTML 页面中…...

C++八股--6--mysql 日志与并发控制

这里向大家介绍一下数据库基础&#xff1a;共分为以下章节 10前序.日志系统 这是数据库的核心。我放到首页来介绍&#xff0c;给大家一个前置概念&#xff0c;方便进行更好的学习 日志文件我们用来记录事务对数据库更新操作的文件&#xff0c;分为以记录为单位的文件和数据块…...

DeepSeek实战--手搓实现Agent

1.背景 要学习AI agent&#xff0c;只会用agent 框架&#xff0c;还不够&#xff0c;一旦框架出现问题&#xff0c;没法快速的排查出问题。 学习就应该“知其然&#xff0c;更应该知其所以然” &#xff0c;今天我们就用编码的方式实现一个简单的agent 。我们模拟一套AI学生评…...

Hutool的`BeanUtil.toBean`方法详解

BeanUtil.toBean是Hutool工具包中一个非常实用的JavaBean转换工具方法&#xff0c;它能够方便地将一个对象&#xff08;通常是Map或另一个JavaBean&#xff09;转换为目标类型的JavaBean实例。 方法签名 public static <T> T toBean(Object source, Class<T> tar…...

线性代数——行列式⭐

目录 一、行列式的定义⭐ 1-1、三阶行列式练习 1-2、下面介绍下三角行列式、上三角行列式、对角行列式 ​编辑 二、行列式的性质 2-1、性质1&#xff0c;2&#xff0c;3&#xff0c;4&#xff0c;5&#xff0c;6 ​编辑 2-2、性质7 2- 3、拉普拉斯定理、克莱姆法则 三…...

iPhone手机连接WiFi异常解决方法

iPhone手机连接WiFi异常解决方法 一、问题现象二、iPhone连不上可能的原因三、基础排查与快速修复第一步:重启大法第二步:忽略网络,重新认证第三步:关闭“私有无线局域网地址”第四步:修改DNS服务器第五步:还原网络设置四、路由器端排查及设置关闭MAC地址过滤或添加到白名…...

Spark缓存

生活中缓存容量受成本和体积限制&#xff08;比如 CPU 缓存只有几 MB 到几十 MB&#xff09;&#xff0c;但会通过算法&#xff08;如 “最近最少使用” 原则&#xff09;智能决定存什么&#xff0c;确保存的是 “最可能被用到的数据”。 1. 为什么需要缓存&#xff1f; 惰性执…...

计算机视觉与深度学习 | 基于Transformer的低照度图像增强技术

基于Transformer的低照度图像增强技术通过结合Transformer的全局建模能力和传统图像增强理论(如Retinex),在保留颜色信息、抑制噪声和平衡亮度方面展现出显著优势。以下是其核心原理、关键公式及典型代码实现: 一、原理分析 1. 全局依赖建模与局部特征融合 Transformer的核…...

学习设计模式《八》——原型模式

一、基础概念 原型模式的本质是【克隆生成对象】&#xff1b; 原型模式的定义&#xff1a;用原型实例指定创建对象的种类&#xff0c;并通过拷贝这些原型创建新的对象 。 原型模式的功能&#xff1a; 1、通过克隆来创建新的对象实例&#xff1b; 2、为克隆出来的新对象实例复制…...

疗愈服务预约小程序源码介绍

基于ThinkPHP、FastAdmin和UniApp开发的疗愈服务预约小程序源码&#xff0c;这款小程序在功能设计和用户体验上都表现出色&#xff0c;为疗愈行业提供了一种全新的服务模式。 该小程序源码采用了ThinkPHP作为后端框架&#xff0c;保证了系统的稳定性和高效性。同时&#xff0c…...

如何通过外网访问内网?对比5个简单的局域网让互联网连接方案

在实际应用中&#xff0c;常常需要从外网访问内网资源&#xff0c;如远程办公访问公司内部服务器、在家访问家庭网络中的设备等。又或者在本地内网搭建的项目应用需要提供互联网服务。以下介绍几种常见的外网访问内网、内网提供公网连接实现方法参考。 一、公网IP路由器端口映…...

Linux 服务器静态 IP 配置初始化指南

✅ 第一步&#xff1a;确认网络管理方式 运行以下命令判断系统使用的网络管理服务&#xff1a; # 检查 NetworkManager 是否活跃 systemctl is-active NetworkManager# 检查 network&#xff08;旧服务&#xff09;是否活跃 systemctl is-active network或者检查配置路径&…...

【随笔】Google学术:but your computer or network may be sending automated queries.

文章目录 一、问题复述二、问题原因三、解决 前提&#xff1a;你的xxx是自己做的&#xff0c;你自己可以管理&#xff0c;而不是用的那些劣质✈场。 一、问题复述 &#x1f7e2;如下图所示&#xff1a;可以打开谷歌学术&#xff0c;但是一搜索就是这个界面。 二、问题原因 …...

长事务:数据库中的“隐形炸弹“——金仓数据库运维避坑指南

引言&#xff1a;凌晨三点的告警 "张工&#xff01;生产库又告警了&#xff01;"凌晨三点的电话铃声总是格外刺耳。运维团队发现数据库频繁进入单用户模式&#xff0c;排查发现某核心表的年龄值&#xff08;Age&#xff09;已突破20亿大关。经过一夜奋战&#xff0c…...

ubuntu nobel + qt5.15.2 设置qss语法识别正确

问题展示 解决步骤 首选项里面的高亮怎么编辑选择都没用。如果已经有generic-highlighter和css.xml&#xff0c;直接修改css.xml文件最直接&#xff01; 在generic-highlighter目录下找到css.xml文件&#xff0c;位置是&#xff1a;/opt/Qt/Tools/QtCreator/share/qtcreator/…...

优化01-统计信息

Oracle 的统计信息是数据库优化器生成高效执行计划的核心依据。它记录了数据库对象&#xff08;如表、索引、列等&#xff09;的元数据信息&#xff0c;帮助优化器评估查询成本并选择最优执行路径。以下是关于 Oracle 统计信息的详细介绍&#xff1a; 一、统计信息的分类 表统…...

Unity-Socket通信实例详解

今天我们来讲解socket通信。 首先我们需要知道什么是socket通信&#xff1a; Socket本质上就是一个个进程之间网络通信的基础&#xff0c;每一个Socket由IP端口组成&#xff0c;熟悉计网的同学应该知道IP主要是应用于IP协议而端口主要应用于TCP协议&#xff0c;这也证明了Sock…...