【开源解析】基于Python的智能文件备份工具开发实战:从定时备份到托盘监控
📁【开源解析】基于Python的智能文件备份工具开发实战:从定时备份到托盘监控
🌈 个人主页:创客白泽 - CSDN博客
🔥 系列专栏:🐍《Python开源项目实战》
💡 热爱不止于代码,热情源自每一个灵感闪现的夜晚。愿以开源之火,点亮前行之路。
👍 如果觉得这篇文章有帮助,欢迎您一键三连,分享给更多人哦
概述
在数字化时代,数据备份已成为个人和企业数据管理的重要环节。本文将详细介绍如何使用Python开发一款功能全面的桌面级文件备份工具,该工具不仅支持即时备份,还能实现定时自动备份、增量备份等专业功能,并具备系统托盘驻留能力。通过tkinter
+ttkbootstrap
构建现代化UI界面,结合pystray
实现后台运行,是Python GUI开发的经典案例。
功能亮点
- 双目录选择:可视化选择源目录和目标目录
- 三种备份模式:
- 立即执行备份
- 每日/每周定时备份
- 精确到分钟的自定义时间备份
- 增量备份机制:仅复制新增或修改过的文件
- 实时日志系统:彩色分级日志输出
- 进度可视化:带条纹动画的进度条
- 托盘驻留:最小化到系统托盘持续运行
- 异常处理:完善的错误捕获和提示机制
技术架构
核心代码解析
1. 增量备份实现
def execute_backup(self):for root, dirs, files in os.walk(self.source_path):rel_path = os.path.relpath(root, self.source_path)dest_path = os.path.join(self.dest_path, rel_path)os.makedirs(dest_path, exist_ok=True)for file in files:src_file = os.path.join(root, file)dest_file = os.path.join(dest_path, file)# 增量判断逻辑if not os.path.exists(dest_file):need_copy = True # 新文件else:src_mtime = os.path.getmtime(src_file)dest_mtime = os.path.getmtime(dest_file)need_copy = src_mtime > dest_mtime # 修改时间比对
这段代码实现了备份工具的核心功能——增量备份。通过对比源文件和目标文件的修改时间,仅当源文件较新时才执行复制操作,大幅提升备份效率。
2. 定时任务调度
def calculate_next_run(self, hour, minute, weekday=None):now = datetime.now()if weekday is not None: # 每周模式days_ahead = (weekday - now.weekday()) % 7next_date = now + timedelta(days=days_ahead)next_run = next_date.replace(hour=hour, minute=minute, second=0)else: # 每日模式next_run = now.replace(hour=hour, minute=minute, second=0)if next_run < now:next_run += timedelta(days=1)return next_run
该算法实现了智能的下一次运行时间计算,支持按日和按周两种循环模式,确保定时任务准确执行。
3. 托盘图标实现
def create_tray_icon(self):image = Image.new('RGBA', (64, 64), (255, 255, 255, 0))draw = ImageDraw.Draw(image)draw.ellipse((16, 16, 48, 48), fill=(33, 150, 243))menu = (pystray.MenuItem("打开主界面", self.restore_window),pystray.MenuItem("立即备份", self.start_backup_thread),pystray.Menu.SEPARATOR,pystray.MenuItem("退出", self.quit_app))self.tray_icon = pystray.Icon("backup_tool", image, menu=menu)threading.Thread(target=self.tray_icon.run).start()
通过Pillow
动态生成托盘图标,结合pystray
创建右键菜单,实现程序后台持续运行能力。
使用教程
基础备份操作
- 点击"选择源目录"按钮指定需要备份的文件夹
- 点击"选择目标目录"按钮设置备份存储位置
- 点击"立即备份"按钮开始执行备份
定时备份设置
- 选择定时类型(每日/每周)
- 设置具体执行时间
- 每日模式:只需设置时分
- 每周模式:需额外选择星期
- 点击"确认定时"按钮保存设置
定时器逻辑层界面用户定时器逻辑层界面用户选择定时类型更新UI选项设置具体时间点击确认按钮计算下次执行时间显示下次备份时间
进阶功能解析
线程安全设计
def start_backup_thread(self):if self.validate_paths():threading.Thread(target=self.execute_backup, daemon=True).start()
采用多线程技术将耗时的备份操作放在后台执行,避免界面卡顿,同时设置为守护线程确保程序能正常退出。
日志系统实现
def log_message(self, message, level="INFO"):color_map = {"INFO": "#17a2b8", "SUCCESS": "#28a745", "WARNING": "#ffc107", "ERROR": "#dc3545"}self.window.after(0, self._append_log, message, level, color_map.get(level))
通过after
方法实现线程安全的日志更新,不同级别日志显示不同颜色,方便问题排查。
完整源码下载
import tkinter as tk
import ttkbootstrap as ttk
from ttkbootstrap.constants import *
from tkinter import filedialog, messagebox, scrolledtext
import shutil
import os
import sys
from datetime import datetime, timedelta
import threading
from PIL import Image, ImageDraw
import pystrayclass BackupApp:def __init__(self):self.window = ttk.Window(themename="litera")self.window.title("文件备份工具")self.window.geometry("465x700")self.window.resizable(False, False)self.window.minsize(465, 700)self.window.maxsize(465, 700)self.window.protocol("WM_DELETE_WINDOW", self.on_close)self.font = ("微软雅黑", 10)self.source_path = ""self.dest_path = ""self.schedule_type = tk.StringVar(value='')self.scheduled_job = Noneself.current_schedule = {}main_frame = ttk.Frame(self.window, padding=20)main_frame.pack(fill=tk.BOTH, expand=True)dir_frame = ttk.Labelframe(main_frame, text="目录设置", padding=15)dir_frame.pack(fill=tk.X, pady=10)dir_frame.grid_columnconfigure(0, weight=0)dir_frame.grid_columnconfigure(1, weight=1)dir_frame.grid_columnconfigure(2, weight=0)ttk.Button(dir_frame,text="选择源目录",command=self.select_source,bootstyle="primary-outline",width=15).grid(row=0, column=0, padx=5, pady=5, sticky="w")self.source_label = ttk.Label(dir_frame, text="未选择源目录", bootstyle="info")self.source_label.grid(row=0, column=1, padx=5, sticky="w")ttk.Button(dir_frame,text="选择目标目录",command=self.select_destination,bootstyle="primary-outline",width=15).grid(row=1, column=0, padx=5, pady=5, sticky="w")self.dest_label = ttk.Label(dir_frame, text="未选择目标目录", bootstyle="info")self.dest_label.grid(row=1, column=1, padx=5, sticky="w")ttk.Button(dir_frame,text="立即备份",command=self.start_backup_thread,bootstyle="success",width=15).grid(row=0, column=2, rowspan=2, padx=15, sticky="ns")schedule_frame = ttk.Labelframe(main_frame, text="定时设置", padding=15)schedule_frame.pack(fill=tk.X, pady=10)type_frame = ttk.Frame(schedule_frame)type_frame.pack(fill=tk.X, pady=5)ttk.Radiobutton(type_frame,text="每日备份",variable=self.schedule_type,value='daily',bootstyle="info-toolbutton",command=self.update_schedule_ui).pack(side=tk.LEFT, padx=5)ttk.Radiobutton(type_frame,text="每周备份",variable=self.schedule_type,value='weekly',bootstyle="info-toolbutton",command=self.update_schedule_ui).pack(side=tk.LEFT)self.settings_container = ttk.Frame(schedule_frame)custom_frame = ttk.Labelframe(main_frame, text="自定义备份(精确到分钟)", padding=15)custom_frame.pack(fill=tk.X, pady=10)custom_frame.grid_columnconfigure(0, weight=1)custom_frame.grid_columnconfigure(1, weight=0)custom_frame.grid_columnconfigure(2, weight=0)self.date_entry = ttk.DateEntry(custom_frame,bootstyle="primary",dateformat="%Y-%m-%d",startdate=datetime.now().date(),width=13)self.date_entry.grid(row=0, column=0, padx=5, sticky="w")time_selector = ttk.Frame(custom_frame)time_selector.grid(row=0, column=1, padx=(5,10), sticky="w")self.custom_hour = ttk.Combobox(time_selector,width=3,values=[f"{i:02d}" for i in range(24)],bootstyle="primary",state="readonly")self.custom_hour.set("09")self.custom_hour.pack(side=tk.LEFT)ttk.Label(time_selector, text=":").pack(side=tk.LEFT)self.custom_minute = ttk.Combobox(time_selector,width=3,values=[f"{i:02d}" for i in range(60)],bootstyle="primary",state="readonly")self.custom_minute.set("00")self.custom_minute.pack(side=tk.LEFT)ttk.Button(custom_frame,text="预定备份",command=self.custom_backup,bootstyle="success",width=10).grid(row=0, column=2, padx=5, sticky="e")log_frame = ttk.Labelframe(main_frame, text="操作日志", padding=15)log_frame.pack(fill=tk.BOTH, expand=True, pady=10)self.log_area = scrolledtext.ScrolledText(log_frame,wrap=tk.WORD,font=("Consolas", 9),height=8,bg="#f8f9fa",fg="#495057")self.log_area.pack(fill=tk.BOTH, expand=True)self.log_area.configure(state="disabled")self.status_label = ttk.Label(main_frame,text="就绪",bootstyle="inverse-default",font=("微软雅黑", 9))self.status_label.pack(fill=tk.X, pady=10)self.progress = ttk.Progressbar(main_frame,orient='horizontal',mode='determinate',bootstyle="success-striped",length=500)self.progress.pack(pady=10)self.window.bind("<Unmap>", self.check_minimized)self.create_tray_icon()def update_schedule_ui(self):for widget in self.settings_container.winfo_children():widget.destroy()time_frame = ttk.Frame(self.settings_container)time_frame.pack(side=tk.LEFT, fill=tk.X, expand=True)ttk.Label(time_frame, text="执行时间:").pack(side=tk.LEFT)self.hour_var = ttk.Combobox(time_frame,width=3,values=[f"{i:02d}" for i in range(24)],bootstyle="primary",state="readonly")self.hour_var.set("09")self.hour_var.pack(side=tk.LEFT, padx=5)ttk.Label(time_frame, text=":").pack(side=tk.LEFT)self.minute_var = ttk.Combobox(time_frame,width=3,values=[f"{i:02d}" for i in range(60)],bootstyle="primary",state="readonly")self.minute_var.set("00")self.minute_var.pack(side=tk.LEFT)if self.schedule_type.get() == 'weekly':weekday_frame = ttk.Frame(self.settings_container)weekday_frame.pack(side=tk.LEFT, padx=20)self.weekday_selector = ttk.Combobox(weekday_frame,values=["星期一","星期二","星期三","星期四","星期五","星期六","星期日"],state="readonly",width=8,bootstyle="primary")self.weekday_selector.pack()self.weekday_selector.set("星期一")ttk.Button(self.settings_container,text="确认定时",command=self.set_schedule,bootstyle="success",width=10).pack(side=tk.RIGHT, padx=10)self.settings_container.pack(fill=tk.X, pady=10)def on_close(self):if messagebox.askokcancel("退出", "确定要退出程序吗?"):self.quit_app()else:self.minimize_to_tray()def check_minimized(self, event):if self.window.state() == 'iconic':self.minimize_to_tray()def minimize_to_tray(self):self.window.withdraw()self.log_message("程序已最小化到托盘", "INFO")def restore_window(self, icon=None, item=None):self.window.deiconify()self.window.attributes('-topmost', 1)self.window.after(100, lambda: self.window.attributes('-topmost', 0))self.log_message("已恢复主窗口", "SUCCESS")def quit_app(self, icon=None, item=None):self.tray_icon.stop()self.window.destroy()sys.exit()def log_message(self, message, level="INFO"):color_map = {"INFO": "#17a2b8", "SUCCESS": "#28a745", "WARNING": "#ffc107", "ERROR": "#dc3545"}self.window.after(0, self._append_log, message, level, color_map.get(level, "#000000"))def _append_log(self, message, level, color):timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")formatted_msg = f"[{timestamp}] {level}: {message}\n"self.log_area.configure(state="normal")self.log_area.insert(tk.END, formatted_msg)self.log_area.tag_add(level, "end-2l linestart", "end-2l lineend")self.log_area.tag_config(level, foreground=color)self.log_area.see(tk.END)self.log_area.configure(state="disabled")def validate_paths(self):errors = []if not os.path.isdir(self.source_path):errors.append("源目录无效或不存在")if not os.path.isdir(self.dest_path):errors.append("目标目录无效或不存在")if errors:messagebox.showerror("路径错误", "\n".join(errors))return Falsereturn Truedef start_backup_thread(self):if self.validate_paths():self.progress["value"] = 0threading.Thread(target=self.execute_backup, daemon=True).start()def execute_backup(self):try:self.log_message("开始备份准备...", "INFO")total_files = sum(len(files) for _, _, files in os.walk(self.source_path))self.log_message(f"发现待处理文件总数: {total_files}", "INFO")copied_files = 0processed_files = 0for root, dirs, files in os.walk(self.source_path):rel_path = os.path.relpath(root, self.source_path)self.log_message(f"正在处理目录: {rel_path}", "INFO")dest_path = os.path.join(self.dest_path, rel_path)os.makedirs(dest_path, exist_ok=True)for file in files:src_file = os.path.join(root, file)dest_file = os.path.join(dest_path, file)need_copy = Falseif not os.path.exists(dest_file):need_copy = Trueself.log_message(f"新增文件: {file}", "INFO")else:src_mtime = os.path.getmtime(src_file)dest_mtime = os.path.getmtime(dest_file)if src_mtime > dest_mtime:need_copy = Trueself.log_message(f"检测到更新: {file}", "INFO")if need_copy:try:shutil.copy2(src_file, dest_file)copied_files += 1except Exception as e:self.log_message(f"文件 {file} 备份失败: {str(e)}", "ERROR")processed_files += 1self.progress["value"] = (processed_files / total_files) * 100self.window.update()self.progress["value"] = 100self.window.after(0, self.show_completion_popup, copied_files)self.window.after(0, self.reschedule_backup)except Exception as e:self.log_message(f"备份失败:{str(e)}", "ERROR")messagebox.showerror("备份失败", str(e))self.progress["value"] = 0finally:self.window.update_idletasks()def show_completion_popup(self, copied_files):popup = tk.Toplevel(self.window)popup.title("备份完成")popup.geometry("300x150+%d+%d" % (self.window.winfo_x() + 100,self.window.winfo_y() + 100))ttk.Label(popup, text=f"成功备份 {copied_files} 个文件", font=("微软雅黑", 12)).pack(pady=20)popup.after(5000, popup.destroy)close_btn = ttk.Button(popup, text="立即关闭", command=popup.destroy,bootstyle="success-outline")close_btn.pack(pady=10)def reschedule_backup(self):if self.current_schedule:try:next_run = self.calculate_next_run(self.current_schedule['hour'],self.current_schedule['minute'],self.current_schedule.get('weekday'))delay = (next_run - datetime.now()).total_seconds()if delay > 0:if self.scheduled_job:self.window.after_cancel(self.scheduled_job)self.scheduled_job = self.window.after(int(delay * 1000),self.start_backup_thread)self.status_label.configure(text=f"下次备份时间: {next_run.strftime('%Y-%m-%d %H:%M')}",bootstyle="inverse-info")self.log_message(f"已更新下次备份时间: {next_run.strftime('%Y-%m-%d %H:%M')}", "SUCCESS")else:self.log_message("无效的时间间隔,定时任务未设置", "ERROR")except Exception as e:self.log_message(f"重新安排定时失败: {str(e)}", "ERROR")def set_schedule(self):try:if self.schedule_type.get() == 'weekly' and not hasattr(self, 'weekday_selector'):messagebox.showwarning("提示", "请选择具体星期")returnself.current_schedule = {'hour': int(self.hour_var.get()),'minute': int(self.minute_var.get()),'weekday': ["星期一","星期二","星期三","星期四","星期五","星期六","星期日"].index(self.weekday_selector.get()) if self.schedule_type.get() == 'weekly' else None}self.reschedule_backup()except Exception as e:self.log_message(f"定时设置失败:{str(e)}", "ERROR")messagebox.showerror("设置错误", str(e))def calculate_next_run(self, hour, minute, weekday=None):now = datetime.now()if weekday is not None:days_ahead = (weekday - now.weekday()) % 7next_date = now + timedelta(days=days_ahead)next_run = next_date.replace(hour=hour, minute=minute, second=0, microsecond=0)if next_run < now:next_run += timedelta(weeks=1)else:next_run = now.replace(hour=hour, minute=minute, second=0, microsecond=0)if next_run < now:next_run += timedelta(days=1)return next_rundef custom_backup(self):try:selected_date = self.date_entry.entry.get()hour = int(self.custom_hour.get())minute = int(self.custom_minute.get())target_time = datetime.strptime(selected_date, "%Y-%m-%d").replace(hour=hour, minute=minute, second=0)if target_time < datetime.now():raise ValueError("时间不能早于当前时刻")delay = (target_time - datetime.now()).total_seconds()if delay <= 0:raise ValueError("定时时间必须晚于当前时间")self.window.after(int(delay * 1000), self.start_backup_thread)self.log_message(f"已预定备份时间:{target_time.strftime('%Y-%m-%d %H:%M')}", "SUCCESS")self.status_label.configure(text=f"预定备份时间: {target_time.strftime('%Y-%m-%d %H:%M')}",bootstyle="inverse-warning")except Exception as e:self.log_message(f"预定失败:{str(e)}", "ERROR")messagebox.showerror("设置错误", str(e))def create_tray_icon(self):try:image = Image.new('RGBA', (64, 64), (255, 255, 255, 0))draw = ImageDraw.Draw(image)draw.ellipse((16, 16, 48, 48), fill=(33, 150, 243))menu = (pystray.MenuItem("打开主界面", self.restore_window),pystray.MenuItem("立即备份", self.start_backup_thread),pystray.Menu.SEPARATOR,pystray.MenuItem("退出", self.quit_app))self.tray_icon = pystray.Icon("backup_tool",image,"数据备份工具",menu=menu)threading.Thread(target=self.tray_icon.run, daemon=True).start()except Exception as e:messagebox.showerror("托盘错误", f"初始化失败: {str(e)}")sys.exit(1)def select_source(self):path = filedialog.askdirectory(title="选择备份源文件夹")if path:self.source_path = pathself.source_label.config(text=path)self.status_label.config(text="源目录已更新", bootstyle="inverse-success")self.log_message(f"源目录设置为: {path}", "INFO")def select_destination(self):path = filedialog.askdirectory(title="选择备份存储位置")if path:self.dest_path = pathself.dest_label.config(text=path)self.status_label.config(text="目标目录已更新", bootstyle="inverse-success")self.log_message(f"目标目录设置为: {path}", "INFO")if __name__ == "__main__":app = BackupApp()app.window.mainloop()
文件结构:
backup_tool/
├── main.py # 主程序入口
├── requirements.txt # 依赖库清单
└── README.md # 使用说明
安装依赖:
pip install -r requirements.txt
总结与扩展
本文开发的备份工具具有以下技术亮点:
- 采用现代化GUI框架ttkbootstrap,界面美观
- 完善的异常处理机制,健壮性强
- 支持后台运行,实用性强
- 增量备份算法节省时间和存储空间
扩展建议:
- 增加云存储支持(如阿里云OSS、七牛云等)
- 添加压缩备份功能
- 实现多版本备份管理
- 增加邮件通知功能
通过本项目的学习,读者可以掌握:
- Python GUI开发进阶技巧
- 定时任务调度实现
- 系统托盘程序开发
- 文件操作最佳实践
“数据备份不是可选项,而是必选项。这个工具用200行代码实现了商业软件的核心功能,值得每个开发者学习。”
相关技术栈:
- Python 3.8+
- tkinter/ttkbootstrap
- pystray
- Pillow
- shutil/os/sys
适用场景:
- 个人文档备份
- 开发项目版本存档
- 服务器重要文件备份
- 自动化运维任务
相关文章:
【开源解析】基于Python的智能文件备份工具开发实战:从定时备份到托盘监控
📁【开源解析】基于Python的智能文件备份工具开发实战:从定时备份到托盘监控 🌈 个人主页:创客白泽 - CSDN博客 🔥 系列专栏:🐍《Python开源项目实战》 💡 热爱不止于代码࿰…...
第四章:基于langchain构造一个完整RAG系统
文章目录 引言一、RAG的基本原理1.1 什么是RAG?1.2 RAG的应用场景 二、RAG系统的构建步骤2.1 环境准备2.2 加载和处理文档2.2.1 文档加载2.2.2 文本分割 2.3 构建嵌入模型2.4 创建向量存储与检索器2.5 检索与生成2.5.1 检索相关文档2.5.2 生成答案 三、完整代码示例…...
uniapp|实现多终端视频弹幕组件、内容轮询、信息表情发送(自定义全屏半屏切换、弹幕启用)
基于UniApp框架实现跨终端视频弹幕组件的开发,结合CSS3动画与setInterval轮询机制,完成弹幕从右向左的动态滚动效果,针对交互需求,设计弹幕启用开关、全屏/半屏模式切换功能,并利用cover-view组件解决原生层级覆盖问题。 目录 引言视频弹幕的交互价值与多终端适配需求Un…...
数据结构(四)——栈的应用—数制转换
利用栈进行数制转换: 十进制转换八进制:先将十进制数除以八得到余数,余数入栈,然后将得到的商继续除以八,直到商为零 #include <stdio.h> #include <stdlib.h>#define MAXSIZE 100//数制转换//定义链表节…...
flinksql bug : Max aggregate function does not support type: CHAR
这个问题是flink中 CHAR 存在语义歧义,主要涉及到位数的关系,这里不做多讨论。 这个问题已经有人提了pr,新版本可以关注是否有解决 这个报错发生在 max(测试字段) ,这个测试字段如果是char 就会报错不支持 解决办法:…...
解决社区录音应用横屏状态下,录音后无法播放的bug
最近看到社区有小伙伴反映,社区录音应用横屏时,录音后无法播放的问题。现分享解决办法。 社区录音应用的来源:https://gitee.com/openharmony/applications_app_samples/tree/OpenHarmony-5.0.2-Release/code/SystemFeature/Media/Recorder …...
【MySQL】存储引擎 - InnoDB详解
📢博客主页:https://blog.csdn.net/2301_779549673 📢博客仓库:https://gitee.com/JohnKingW/linux_test/tree/master/lesson 📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正! &…...
软件工程之形式化说明技术深度解析
按照形式化的程度,可以把软件工程使用的方法划分成非形式化、半形式化和形式化3种。用自然语言描述需求规格说明书,是典型的非形式化方法。用数据流图或实体-联系图建立模型,是典型的半形式化方法。 所谓形式化方法,是描述系统性…...
Nacos源码—6.Nacos升级gRPC分析一
大纲 1.Nacos 2.x版本的一些变化 2.客户端升级gRPC发起服务注册 3.服务端进行服务注册时的处理 4.客户端服务发现和服务端处理服务订阅的源码分析 1.Nacos 2.x版本的一些变化 变化一:客户端和服务端的交互方式由HTTP升级为gRPC Nacos 1.x服务端会提供一系列的…...
使用 React 实现语音识别并转换功能
在现代 Web 开发中,语音识别技术的应用越来越广泛。它为用户提供了更加便捷、自然的交互方式,例如语音输入、语音指令等。本文将介绍如何使用 React 实现一个简单的语音识别并转换的功能。 功能概述 我们要实现的功能是一个语音识别测试页面࿰…...
2.5 点云数据存储格式——大型点云传输格式
通常,进行大型点云数据传输时,一般采用一种后缀为bin的文...
Windows系统下使用Kafka和Zookeeper,Python运行kafka(一)
下载和安装见Linux系统下使用Kafka和Zookeeper 配置 Zookeeper Zookeeper 是 Kafka 所依赖的分布式协调服务。在 Kafka 解压目录下,有一个 Zookeeper 的配置文件模板config/zookeeper.properties,你可以直接使用默认配置。 启动 Zookeeper 打开命令提示符(CMD),进入 K…...
数据结构(三)——栈和队列
一、栈和队列的定义和特点 栈:受约束的线性表,只允许栈顶元素入栈和出栈 对栈来说,表尾端称为栈顶,表头端称为栈底,不含元素的空表称为空栈 先进后出,后进先出 队列:受约束的线性表࿰…...
零基础入门Hadoop:IntelliJ IDEA远程连接服务器中Hadoop运行WordCount
今天我们来聊一聊大数据,作为一个Hadoop的新手,我也并不敢深入探讨复杂的底层原理。因此,这篇文章的重点更多是从实际操作和入门实践的角度出发,带领大家一起了解大数据应用的基本过程。我们将通过一个经典的案例——WordCounter&…...
在Postman中高效生成测试接口:从API文档到可执行测试的完整指南
引言 在API开发与测试流程中,Postman是一款高效的工具,能将API文档快速转化为可执行的测试用例。本文以《DBC协议管理接口文档》为例,详细讲解如何通过Postman实现接口的创建、配置、批量生成及自动化测试,帮助开发者和测试人员提升效率,确保接口质量。 一、准备工作:理…...
飞云分仓操盘副图指标操作技术图文分解
如上图,副图指标-飞云分仓操盘指标,指标三条线蓝色“首峰线”,红色“引力1”,青色“引力2”,多头行情时“首峰线”和“引力1”之间显示为红色,“引力1”和“引力2”多头是区间颜色显示为紫色。 如上图图标信…...
K8s中的containerPort与port、targetPort、nodePort的关系:
pod中的containerPort与service中的port、targetPort、nodePort的关系: 1、containerPort为pod的配置,对应pod内部服务监听的具体端口,例如nginx服务默认监听80端口,那么nginx的pod的containerPort应该配置为80,例如m…...
jquery+ajax+SpringBoot实现前后端分离技术
一、前端方面: 第1步,在前端HTML页面的头部引入jquery <head><meta http-equiv"Content-Type" content"text/html;charsetUTF-8"><title>XXX</title><link rel"stylesheet" type"text/…...
阀门产业发展方向报告(石油化工阀门应用技术交流大会)
本文大部分内容来自中国通用机械工业协会副会长张宗列在“2024全国石油化工阀门应用技术交流大会”上发表的报告。 一、国外阀门产业发展 从全球阀门市场分布看,亚洲是最大的工业阀门市场,美洲是全球第二大工业阀门市场,欧洲位列第三。 从国…...
华为云Astro后端开发中对象、事件、脚本、服务编排、触发器、工作流等模块的逻辑关系如何?以iotDA数据传输过程举例演示元素工作过程
目录 🏭 类比总览:低代码平台就像一座自动化工厂 🧱 1. 对象(Object) = 工厂里的“原材料仓库” 🧱 2. 结构体(Structure) = 自定义的“装配模具” 🔔 3. 事件(Event) = 触发的“感应器” ✍️ 4. 脚本(Script) = 后台的“逻辑处理代码” ⚙️ 5. 服务编…...
面向小型企业顶点项目的网络安全咨询人机协作框架
1. 简介 1.1. 背景和动机 由于小型企业无法访问结构化系统,且缺乏大型组织通常拥有的专用资源,它们经常面临巨大的网络安全挑战 [ [1 ]。为大型企业设计的网络安全框架通常对小型企业来说过于复杂且不切实际,导致它们容易受到复杂的网络威胁 2 ]。这种复杂性可能导致小型…...
RSAC 2025观察:零信任+AI=网络安全新范式
2025年4月28日~5月1日,全球最具影响力的网络安全盛会RSAC 2025在美国旧金山举办,吸引了全球44,000名网络安全从业者参与。大会以“Many Voices. One Community.”为主题,聚焦AI安全、供应链风险、零信任等核心议题。其中,AI Agent…...
ruoyi-flowable-plus 前端框架启动报错修复
版本 1. ruoyi-flowable-plus 前端框架启动报错修复 启动时设置环境变量 "scripts": {"dev": "SET NODE_OPTIONS--openssl-legacy-provider && vue-cli-service serve","build:prod": "vue-cli-service build",&qu…...
安全可控·高效响应|北峰智能互通矿业通信系统解决方案
项目概况 随着矿业行业工作环境日益复杂,涵盖地下开采、露天挖掘、矿物运输及深加工等多个环节,作业区域呈现广阔且分散的特点,往往存在诸多安全风险。当面临突发事故,由于应急救援体系不完善,救援通信系统相对落后&a…...
ubuntu查看安装的软件包的位置
在 Ubuntu 中,libcli11-dev 是一个 头文件库(header-only),因此它不会像动态库(.so 文件)那样有明确的下载路径。但你可以通过以下方法查看它的安装位置: 1. 查看 libcli11-dev 安装的文件 使用…...
【金仓数据库征文】金仓数据库 KES 助力企业数据库迁移的实践路径
在企业数字化转型浪潮的强力推动下,数据库迁移已成为企业升级 IT 架构、提升数据管理能力的关键环节。从 MySQL 到金仓数据库 KingbaseES(KES)的迁移方案,为企业提供了一条高效、可靠的数据库升级路径。 一、迁移挑战与金仓数据…...
Nginx1.26.2安装包编译安装并配置stream模块
准备nginx安装文件:nginx-1.26.2.tar.gz cd /usr/local wget http://nginx.org/download/nginx-1.26.2.tar.gz tar -zxvf nginx-1.26.2.tar.gz && cd nginx-1.26.2 1.创建安装目录 mkdir nginx 2.解压安装文件nginx-1.26.2.tar.gz tar -zxvf nginx-1.26…...
kotlin @JvmStatic注解的作用和使用场景
1. JvmStatic 的作用 JvmStatic 是 Kotlin 提供的一个注解,用于在 JVM 上将伴生对象(companion object)中的方法或属性暴露为 Java 静态方法或字段。 作用对象:只能用在 companion object 中的函数或属性。效果: 在 …...
Blind SSRF with Shellshock exploitation过关
Blind SSRF with Shellshock exploitation 生活就像一杯咖啡,苦与甜都是必需的,关键是要学会享受每一口。 先说通关方法: 1.首先在bp的扩展商店安装插件 Collaborator Everywhere 2.进入靶场首页 复制url https://0af600d3048daad080e6…...
2025-05-08 Unity 网络基础9——FTP通信
文章目录 1 FTP1.1 工作原理1.2 传输模式 2 搭建 FTP 服务器2.1 启用服务2.2 配置站点2.3 设置防火墙2.4 指定用户登录 3 常用 API3.1 NetworkCredential3.2 FtpWebRequest3.3 FtpWebResponse 4 实战操作4.1 上传文件4.2 下载文件4.3 删除文件4.4 获取文件大小4.5 创建文件夹4.…...
3.2.3 掌握RDD转换算子 - 5. 合并算子 - union()
在本节课中,我们学习了Spark RDD的union()算子,它能够将两个数据类型一致的RDD合并为一个新的RDD,主要用于整合不同数据源。通过案例演示,我们成功将两个简单的数字RDD合并,直观地看到合并结果是按原顺序纵向拼接&…...
数据来源合法性尽职调查:保障权益的关键防线
首席数据官高鹏律师团队 在当今数字化时代,数据已成为企业和个人最为宝贵的资产之一。然而,伴随着数据的广泛应用与流通,其来源的合法性问题愈发凸显,犹如隐藏在暗处的礁石,稍不留神就可能让涉事主体陷入法律的漩涡。…...
sui在windows虚拟化子系统Ubuntu和纯windows下的安装和使用
一、sui在windows虚拟化子系统Ubuntu下的安装使用(WindowsWsl2Ubuntu24.04) 前言:解释一下WSL、Ubuntu的关系 WSL(Windows Subsystem for Linux)是微软推出的一项功能,允许用户在 Windows 系统中原生运行…...
springmvc的入门案例
springmvc的概述 SpringMVC的概述 是一种基于Java实现的MVC设计模型的请求驱动类型的轻量级WEB框架。Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。使用 Spring 可插入的 MVC 架…...
【MCP】为什么使用Streamable HTTP: 相比SSE的优势与实践指南
在现代Web开发中,实时通信已经成为许多应用的核心需求。从聊天应用到股票市场更新,从游戏服务器到AI模型通信,各种技术应运而生以满足这些需求。最近,Model Context Protocol (MCP) 引入了一种新的传输机制 —— Streamable HTTP&…...
CentOS的防火墙工具(firewalld和iptables)的使用
CentOS的防火墙工具因版本不同而异,以下是具体操作步骤: 一、firewalld(CentOS 7及以上默认工具) 1、安装与启动: 安装:sudo yum install firewalld 启动服务:sudo systemctl start fir…...
解析小米大模型MiMo:解锁语言模型推理潜力
一、基本介绍 1.1 项目背景 在大型语言模型快速发展的背景下,小米AI团队推出MiMo系列模型,突破性地在7B参数规模上实现卓越推理能力。传统观点认为32B以上模型才能胜任复杂推理任务,而MiMo通过创新的训练范式证明:精心设计的预训练和强化学习策略,可使小模型迸发巨大推理…...
web 自动化之 Selenium 元素定位和浏览器操作
文章目录 一、元素定位的八大方法1、基于 id/name/class/tag_name 定位2、基于 a 标签元素的链接文本定位3、基于xpath定位4、css定位 二、浏览器操作1、信息获取2、 浏览器关闭3、 浏览器控制 一、元素定位的八大方法 web 自动化测试就是通过代码对网页进行测试,在…...
vscode如何使用 GitHub Copilot
1.在vscode中扩展工具栏搜索“copilot”,选择GitHub Copilot安装。 2.使用快捷键CtrlAltI 打开聊天界面,输入问题后回车即可使用。 注意: 使用copilot需要使用GitHub账号先登录,如果打不开登录页面,需要修改host文件&a…...
AWS之存储服务
存储术语 分类 接口/技术类型 应用场景特点 关系及区别 机械硬盘接口 IDE(Integrated Drive Electronics) 早期用于个人电脑,现已逐渐淘汰 机械硬盘接口、固态硬盘接口是硬盘与主机或其他设备连接的物理和协议规范; FC - …...
安装 Docker
一、CentOS 系统安装 Docker 1. 卸载旧版本(如有) sudo yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine 2. 安装依赖工具 sudo yum install -y…...
代理协议解析:如何根据需求选择HTTP、HTTPS或SOCKS5?
在现代网络中,代理服务器是一种常见的工具,用于提高安全性、匿名性和访问速度。常见的代理协议包括HTTP、HTTPS和SOCKS5。本文将详细解析这三种代理协议,并帮助您根据具体需求选择最合适的代理协议。 一、HTTP代理 1.1 特点 用途广泛&…...
用于构建安全AI代理的开源防护系统
大家读完觉得有帮助记得及时关注!!! 大型语言模型(LLMs)已经从简单的聊天机器人演变为能够执行复杂任务的自主代理,例如编辑生产代码、编排工作流程以及基于不受信任的输入(如网页和电子邮件&am…...
CTF-DAY10
[SWPUCTF 2021 新生赛]zipbomb 题目描述: 请注意,不要以任何方式尝试完全解压该文件,运存被塞满后果自负。请尝试分析该文件。 使用WinRAR解压打开 CTFSHOW刷题 crypto11 密文:a8db1d82db78ed452ba0882fb9554fc 提交 flag{明…...
WHAT - react-query(TanStack Query) vs swr 请求
文章目录 react-query什么是 TanStack Query(原 React Query)核心特性 TanStack Query vs SWR 对比具体特性对比哪个更适合你 总结 react-query react-query(现已更名为 TanStack Query)和 SWR 一样,都是专注于 远程数…...
WebFlux与HttpStreamable关系解析
1-Streamable 1-WebFlux与HttpStreamable关系解析2-MCP协议Streamable HTTP 2-参考网址 MCP协议Streamable HTTPMCP协议重大升级,Spring AI Alibaba联合Higress发布业界首个Streamable HTTP实现方案 3-WebFlux与HttpStreamable关系解析 WebFlux 和 HttpStreamabl…...
深度学习工程化:基于TensorFlow的模型部署全流程详解
深度学习工程化:基于TensorFlow的模型部署全流程详解 引言 在深度学习项目中,模型训练只是第一步,将模型成功部署到生产环境才是真正创造价值的关键。本文将全面介绍TensorFlow模型从训练到部署的完整工程化流程,涵盖多种部署场…...
RAG技术在测试用例生成中的应用
测试用例中的 RAG 通常指 Retrieval-Augmented Generation(检索增强生成) 在测试领域的应用,是一种结合检索与生成的技术方法,用于自动化生成或优化测试用例。 核心概念 RAG 技术背景: • RAG 最初由 Meta 提出…...
uniapp + vue3 + 京东Nut动作面板组件:实现登录弹框组件(含代码、案例、小程序截图)
uniapp + vue3 + 京东Nut动作面板组件:实现登录弹框组件(含代码、案例、小程序截图) 代码示下,不再赘述。 动作面板组件:https://nutui-uniapp.netlify.app/components/feedback/actionsheet.html 项目背景 业务需求 描述: uniapp + vue3 + 京东Nut框架:实现登录弹框组…...
在登录页面上添加验证码
这是一个简单的登录页面,里面必须通过验证码通过之后才能够进入页面 创建一个servlet(验证码的) package qcby.util;import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; im…...