正文
工作中,每个月都会对数据进行汇总,想要方便一些,就写了一个文件校验器。
不同于市面上常见的批量重命名,这个具有自动校验功能,
[color=]可以检验文件名的连续性
,会提示缺失的文件,同时,还会校验文件数量,MD5值,路径等。
功能
1.快速批量校验MD5值校验。
2.文件大小、文件路径显示
3.文件日期连续性校验,对缺失日期文件进行提示。(不完善)
4.搜索框支持中文搜索
5.对小于。方便快速定位异常文件
以下是界面截图&源代码&打包文件
1.界面及功能截图
1725602252954.jpg (213.33 KB, 下载次数: 0)
下载附件
界面
2024-9-6 13:57 上传
2.源代码
[Python] 纯文本查看 复制代码import os
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
from datetime import datetime
import hashlib
import math
import re
class FileVerifier:
def __init__(self, master):
self.master = master
master.title("文件校验")
self.folder_path = tk.StringVar()
self.filter_rule = tk.StringVar()
self.create_widgets()
self.tree = self.create_treeview()
self.context_menu = self.create_context_menu()
self.file_paths = {}
def create_widgets(self):
# 使用Frame来组织并集中管理其他所有Widget
self.main_frame = tk.Frame(self.master)
self.main_frame.pack(fill=tk.BOTH, expand=True)
tk.Label(self.main_frame, text="文件夹路径:").grid(row=0, column=0, sticky="w")
# 增加sticky参数以确保控件填满单元格并左对齐
tk.Entry(self.main_frame, textvariable=self.folder_path).grid(row=0, column=1, sticky="we")
tk.Button(self.main_frame, text="浏览", command=self.select_folder).grid(row=0, column=2, sticky="e")
tk.Label(self.main_frame, text="文件名匹配规则:").grid(row=1, column=0, sticky="w")
tk.Entry(self.main_frame, textvariable=self.filter_rule).grid(row=1, column=1, sticky="we")
tk.Button(self.main_frame, text="开始校验", command=self.verify_files).grid(row=1, column=2, sticky="e")
def create_treeview(self):
columns = ('status', 'filename', 'size', 'modified', 'md5', 'path')
tree = ttk.Treeview(self.master, columns=columns, show='headings')
scrollbar = ttk.Scrollbar(self.master, orient=tk.VERTICAL, command=tree.yview)
tree.configure(yscrollcommand=scrollbar.set)
for col in columns:
tree.heading(col, text=col.capitalize())
tree.column(col, width=100)
tree.pack(fill=tk.BOTH, expand=True)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
return tree
def create_context_menu(self):
context_menu = tk.Menu(self.master, tearoff=0)
context_menu.add_command(label="打开文件", command=self.open_file)
context_menu.add_command(label="在 Windows 资源管理器中打开", command=self.open_file_in_explorer)
return context_menu
def select_folder(self):
folder_selected = filedialog.askdirectory()
if folder_selected:
self.folder_path.set(folder_selected)
def show_context_menu(self, event):
# 获取选中的项
iid = self.tree.identify_row(event.y)
if iid:
self.tree.selection_set(iid)
self.context_menu.post(event.x_root, event.y_root)
def open_file(self):
selected_item = self.tree.selection()
if selected_item:
file_path = self.file_paths[selected_item[0]]
if os.path.isfile(file_path):
os.startfile(file_path)
def open_file_in_explorer(self):
selected_item = self.tree.selection()
if selected_item:
file_path = self.file_paths[selected_item[0]]
file_dir = os.path.dirname(file_path)
os.startfile(file_dir)
def get_file_size(self, size):
if size >= 1024 * 1024:
return f"{size / (1024 * 1024):.2f} MB"
elif size >= 1024:
return f"{size / 1024:.2f} KB"
else:
return f"{size} B"
def calculate_md5(self, filename):
hash_md5 = hashlib.md5()
with open(filename, "rb") as f:
for chunk in iter(lambda: f.read(4096), b""):
hash_md5.update(chunk)
return hash_md5.hexdigest()
def verify_files(self):
folder_path = self.folder_path.get()
filter_rule = self.filter_rule.get()
if not folder_path:
messagebox.showerror("错误", "请选择文件夹路径!")
return
if not filter_rule:
messagebox.showerror("错误", "请输入文件名匹配规则!")
return
file_count = 0
self.tree.delete(*self.tree.get_children()) # 清空Treeview
self.file_paths.clear() # 清空文件路径字典
for root, dirs, files in os.walk(folder_path):
for name in files:
if filter_rule in name:
file_path = os.path.join(root, name)
file_size = os.path.getsize(file_path)
file_size_str = self.get_file_size(file_size)
modification_time = os.path.getmtime(file_path)
formatted_modification_time = datetime.fromtimestamp(modification_time).strftime('%Y-%m-%d %H:%M:%S')
md5 = self.calculate_md5(file_path)
status = "Ok" if file_size >= 10 * 1024 else "异常文件"
self.tree.insert('', tk.END, values=(status, name, file_size_str, formatted_modification_time, md5, file_path))
self.file_paths[self.tree.get_children()[-1]] = file_path
file_count += 1
self.master.update_idletasks()
self.master.minsize(self.tree.winfo_width(), self.tree.winfo_height())
messagebox.showinfo("完成", f"校验完成。共找到 {file_count} 个文件。")
self.check_file_date_continuity(files)
def check_file_date_continuity(self, file_list):
date_list = []
missing_dates = []
for file_name in file_list:
match = re.search(r'\d{8}', file_name)
if match:
date_str = match.group()
date = datetime.strptime(date_str, '%Y%m%d')
date_list.append(date)
date_list.sort()
for i in range(len(date_list) - 1):
if (date_list[i + 1] - date_list).days > 1:
missing_dates.append(date_list[i + 1])
if missing_dates:
message = "以下日期的文件缺失:\n"
for date in missing_dates:
message += f"{date.strftime('%Y-%m-%d')}\n"
messagebox.showwarning("警告", message)
else:
messagebox.showinfo("通知", "文件名日期连续,没有缺失。")
if __name__ == "__main__":
root = tk.Tk()
app = FileVerifier(root)
root.mainloop()
打包好的EXE(不放心的,可以审查源码。打包只是方便使用)
virscan检测报告:https://www.virscan.org/report/aaf8c24604039827cd9b95a40550b893a01052a61b85469dfd6d051ee0f80533
蓝奏:https://wwi.lanzoup.com/iYcdr29c201c 密码:52pj