【开源】Python打造高效剪贴板历史管理器:实现跨平台生产力工具
📋【开源】Python打造高效剪贴板历史管理器:实现跨平台生产力工具
🌈 个人主页:创客白泽 - CSDN博客
🔥 系列专栏:🐍《Python开源项目实战》
💡 热爱不止于代码,热情源自每一个灵感闪现的夜晚。愿以开源之火,点亮前行之路。
👍 如果觉得这篇文章有帮助,欢迎您一键三连,分享给更多人哦
一、概述:为什么需要剪贴板历史管理?
在日常工作和编程中,剪贴板是我们使用最频繁的功能之一。但Windows自带的剪贴板只能保存最近一次的内容,当我们需要回溯之前复制过的内容时,就显得力不从心。本文将介绍如何使用Python和PyQt5开发一个功能强大的剪贴板历史管理器,具有以下特点:
- 实时监控剪贴板变化,自动保存历史记录
- 支持快捷键快速粘贴历史内容(Ctrl+D+数字)
- 美观的GUI界面,支持多种主题切换
- 系统托盘运行,不占用任务栏空间
- 历史记录持久化保存,重启不丢失
- 内容搜索和分类管理功能
这个工具特别适合程序员、文字工作者和需要频繁复制粘贴的用户群体,能显著提高工作效率。
二、功能特性全解析
2.1 核心功能
- 剪贴板监控:实时检测剪贴板变化,自动保存新内容
- 历史记录管理:支持查看、复制、粘贴、删除历史记录
- 快速访问:通过快捷键(Ctrl+D+数字)快速粘贴最近9条记录
- 内容搜索:支持关键词搜索历史记录
- 数据持久化:自动保存历史记录到JSON文件
2.2 增强功能
- 多主题支持:提供默认、深色、蓝色、绿色、粉色五种主题
- 系统托盘集成:最小化到托盘,不影响工作区
- 智能去重:自动过滤连续重复内容
- 内容预览:列表显示内容摘要,点击查看完整内容
- 可配置选项:
- 设置历史记录最大数量(10-500条)
- 启用/禁用快捷键
- 切换自动粘贴功能
- 设置开机启动(需额外配置)
三、效果展示
3.1 主界面
界面采用左右分栏设计:
- 左侧:历史记录列表,按时间倒序排列
- 右侧:详情查看区和功能操作区
四、实现步骤详解
4.1 环境准备
pip install PyQt5 keyboard pyperclip
4.2 项目结构
clipboard_manager/
│── main.py # 主程序
│── clipboard_history.json # 历史记录存储文件
│── icons/ # 图标资源
│ ├── icon16.png
│ ├── icon32.png
│ ├── icon48.png
│ └── icon256.png
4.3 核心实现流程
-
初始化应用:
- 创建QApplication和主窗口
- 设置系统托盘图标
- 加载历史记录文件
-
剪贴板监控:
self.clipboard_timer = QTimer(self)self.clipboard_timer.timeout.connect(self.check_clipboard)self.clipboard_timer.start(500) # 每500ms检查一次
-
历史记录管理:
- 使用列表存储历史记录,每个记录包含内容、时间戳和预览
- 实现添加、删除、清空等操作
- 自动限制最大记录数
-
快捷键处理:
keyboard.add_hotkey(f'ctrl+d+{i}', lambda i=i: self.paste_from_history(i-1))
-
UI构建:
- 使用QVBoxLayout和QHBoxLayout构建灵活布局
- 为各组件添加样式表美化界面
- 实现主题切换功能
五、关键代码解析
5.1 剪贴板监控实现
def check_clipboard(self):"""检查剪贴板内容是否变化"""current_clipboard = pyperclip.paste()if current_clipboard and (not self.history or current_clipboard != self.history[0]['content']):self.add_to_history(current_clipboard)
这段代码通过定时器定期检查剪贴板内容,当发现新内容且与最近记录不同时,将其添加到历史记录中。
5.2 历史记录数据结构
history_item = {'content': content, # 完整内容'timestamp': datetime.now().strftime("%Y-%m-%d %H:%M:%S"), # 时间戳'preview': content[:50] + ("..." if len(content) > 50 else "") # 预览
}
每个历史记录项都包含这三个字段,便于显示和管理。
5.3 快捷键处理
def paste_from_history(self, index):"""通过快捷键粘贴指定索引的历史记录"""if 0 <= index < len(self.history):pyperclip.copy(self.history[index]['content'])if self.auto_paste:keyboard.send('ctrl+v')
这段代码实现了通过快捷键快速粘贴历史记录的功能,同时支持自动粘贴模式。
5.4 主题切换实现
def change_theme(self, theme_name):"""更改应用程序主题"""if theme_name == "默认":self.setStyleSheet("")elif theme_name == "深色":self.set_dark_theme()# 其他主题...
通过动态修改样式表(QSS)实现主题切换,每种主题定义了不同的颜色方案。
六、完整源码下载
import sys
import os
import json
import keyboard
import pyperclip
from datetime import datetime
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QListWidget, QPushButton, QLabel, QLineEdit, QTextEdit, QComboBox, QSpinBox, QCheckBox, QMessageBox, QSystemTrayIcon, QMenu, QAction, QStyle, QListWidgetItem)
from PyQt5.QtCore import Qt, QTimer, QSize
from PyQt5.QtGui import QIcon, QColor, QPalette, QFont, QBrushclass ClipboardHistoryApp(QMainWindow):def __init__(self):super().__init__()# 初始化设置self.history = []self.max_history = 100self.hotkeys_enabled = Trueself.auto_paste = Trueself.start_with_system = Falseself.history_file = "clipboard_history.json"# 加载历史记录self.load_history()# 初始化UIself.init_ui()# 设置系统托盘self.init_system_tray()# 设置定时器检查剪贴板变化self.clipboard_timer = QTimer(self)self.clipboard_timer.timeout.connect(self.check_clipboard)self.clipboard_timer.start(500) # 每500毫秒检查一次# 注册全局快捷键self.register_hotkeys()# 设置窗口样式self.set_window_style()def init_ui(self):"""初始化用户界面"""self.setWindowTitle("剪贴板历史管理器")self.setGeometry(100, 100, 800, 600)# 主窗口部件main_widget = QWidget()self.setCentralWidget(main_widget)# 主布局main_layout = QHBoxLayout()main_widget.setLayout(main_layout)# 左侧面板 - 历史记录列表left_panel = QWidget()left_layout = QVBoxLayout()left_panel.setLayout(left_layout)self.history_list = QListWidget()self.history_list.setStyleSheet("""QListWidget {background-color: #f0f0f0;border: 1px solid #ccc;border-radius: 5px;padding: 5px;}QListWidget::item {padding: 8px;border-bottom: 1px solid #ddd;}QListWidget::item:hover {background-color: #e0e0e0;}QListWidget::item:selected {background-color: #4CAF50;color: white;}""")self.history_list.itemClicked.connect(self.show_selected_item)left_layout.addWidget(QLabel("剪贴板历史记录:"))left_layout.addWidget(self.history_list)# 右侧面板 - 详情和设置right_panel = QWidget()right_layout = QVBoxLayout()right_panel.setLayout(right_layout)# 详情区域detail_group = QWidget()detail_layout = QVBoxLayout()detail_group.setLayout(detail_layout)self.detail_text = QTextEdit()self.detail_text.setReadOnly(True)self.detail_text.setStyleSheet("""QTextEdit {background-color: #f9f9f9;border: 1px solid #ccc;border-radius: 5px;padding: 10px;min-height: 150px;}""")detail_layout.addWidget(QLabel("内容详情:"))detail_layout.addWidget(self.detail_text)# 操作按钮button_group = QWidget()button_layout = QHBoxLayout()button_group.setLayout(button_layout)self.copy_btn = QPushButton("复制选中项")self.copy_btn.setStyleSheet("""QPushButton {background-color: #4CAF50;color: white;border: none;padding: 8px;border-radius: 4px;}QPushButton:hover {background-color: #45a049;}""")self.copy_btn.clicked.connect(self.copy_selected)self.paste_btn = QPushButton("粘贴选中项")self.paste_btn.setStyleSheet("""QPushButton {background-color: #008CBA;color: white;border: none;padding: 8px;border-radius: 4px;}QPushButton:hover {background-color: #0077A3;}""")self.paste_btn.clicked.connect(self.paste_selected)self.delete_btn = QPushButton("删除选中项")self.delete_btn.setStyleSheet("""QPushButton {background-color: #f44336;color: white;border: none;padding: 8px;border-radius: 4px;}QPushButton:hover {background-color: #d32f2f;}""")self.delete_btn.clicked.connect(self.delete_selected)# 新增清空历史按钮self.clear_btn = QPushButton("清空历史")self.clear_btn.setStyleSheet("""QPushButton {background-color: #ff9800;color: white;border: none;padding: 8px;border-radius: 4px;}QPushButton:hover {background-color: #e68a00;}""")self.clear_btn.clicked.connect(self.clear_history)button_layout.addWidget(self.copy_btn)button_layout.addWidget(self.paste_btn)button_layout.addWidget(self.delete_btn)button_layout.addWidget(self.clear_btn)# 搜索区域search_group = QWidget()search_layout = QHBoxLayout()search_group.setLayout(search_layout)self.search_input = QLineEdit()self.search_input.setPlaceholderText("搜索剪贴板历史...")self.search_input.textChanged.connect(self.search_history)self.search_input.setStyleSheet("""QLineEdit {padding: 8px;border: 1px solid #ccc;border-radius: 4px;}""")search_btn = QPushButton("搜索")search_btn.setStyleSheet("""QPushButton {background-color: #555;color: white;border: none;padding: 8px 15px;border-radius: 4px;margin-left: 5px;}QPushButton:hover {background-color: #444;}""")search_btn.clicked.connect(self.search_history)search_layout.addWidget(self.search_input)search_layout.addWidget(search_btn)# 设置区域settings_group = QWidget()settings_layout = QVBoxLayout()settings_group.setLayout(settings_layout)settings_layout.addWidget(QLabel("设置:"))# 历史记录限制history_limit_layout = QHBoxLayout()history_limit_layout.addWidget(QLabel("最大历史记录数:"))self.history_limit_spin = QSpinBox()self.history_limit_spin.setRange(10, 500)self.history_limit_spin.setValue(self.max_history)self.history_limit_spin.valueChanged.connect(self.update_history_limit)history_limit_layout.addWidget(self.history_limit_spin)settings_layout.addLayout(history_limit_layout)# 快捷键设置hotkey_layout = QHBoxLayout()self.hotkey_checkbox = QCheckBox("启用快捷键 (Ctrl+D+数字)")self.hotkey_checkbox.setChecked(self.hotkeys_enabled)self.hotkey_checkbox.stateChanged.connect(self.toggle_hotkeys)hotkey_layout.addWidget(self.hotkey_checkbox)settings_layout.addLayout(hotkey_layout)# 自动粘贴设置auto_paste_layout = QHBoxLayout()self.auto_paste_checkbox = QCheckBox("使用快捷键时自动粘贴")self.auto_paste_checkbox.setChecked(self.auto_paste)self.auto_paste_checkbox.stateChanged.connect(self.toggle_auto_paste)auto_paste_layout.addWidget(self.auto_paste_checkbox)settings_layout.addLayout(auto_paste_layout)# 开机启动设置startup_layout = QHBoxLayout()self.startup_checkbox = QCheckBox("开机自动启动")self.startup_checkbox.setChecked(self.start_with_system)self.startup_checkbox.stateChanged.connect(self.toggle_start_with_system)startup_layout.addWidget(self.startup_checkbox)settings_layout.addLayout(startup_layout)# 主题选择theme_layout = QHBoxLayout()theme_layout.addWidget(QLabel("主题:"))self.theme_combo = QComboBox()self.theme_combo.addItems(["默认", "深色", "蓝色", "绿色", "粉色"])self.theme_combo.currentTextChanged.connect(self.change_theme)theme_layout.addWidget(self.theme_combo)settings_layout.addLayout(theme_layout)# 添加所有右侧组件right_layout.addWidget(detail_group)right_layout.addWidget(button_group)right_layout.addWidget(search_group)right_layout.addWidget(settings_group)# 添加左右面板到主布局main_layout.addWidget(left_panel, 70)main_layout.addWidget(right_panel, 30)# 更新历史记录列表self.update_history_list()def set_window_style(self):"""设置窗口样式"""self.setStyleSheet("""QMainWindow {background-color: #f5f5f5;}QLabel {font-weight: bold;color: #333;}QGroupBox {border: 1px solid #ddd;border-radius: 5px;margin-top: 10px;padding-top: 15px;}QGroupBox::title {subcontrol-origin: margin;left: 10px;padding: 0 3px;}""")def init_system_tray(self):"""初始化系统托盘"""self.tray_icon = QSystemTrayIcon(self)self.tray_icon.setIcon(self.style().standardIcon(QStyle.SP_ComputerIcon))tray_menu = QMenu()show_action = QAction("显示", self)show_action.triggered.connect(self.show)tray_menu.addAction(show_action)hide_action = QAction("隐藏", self)hide_action.triggered.connect(self.hide)tray_menu.addAction(hide_action)quit_action = QAction("退出", self)quit_action.triggered.connect(self.quit_app)tray_menu.addAction(quit_action)self.tray_icon.setContextMenu(tray_menu)self.tray_icon.show()self.tray_icon.activated.connect(self.tray_icon_activated)def tray_icon_activated(self, reason):"""系统托盘图标被激活时的处理"""if reason == QSystemTrayIcon.DoubleClick:self.show()def closeEvent(self, event):"""重写关闭事件,最小化到托盘"""event.ignore()self.hide()self.tray_icon.showMessage("剪贴板历史管理器","程序已最小化到系统托盘",QSystemTrayIcon.Information,2000)def register_hotkeys(self):"""注册全局快捷键"""if self.hotkeys_enabled:try:# 注册Ctrl+D+数字1-9的快捷键for i in range(1, 10):keyboard.add_hotkey(f'ctrl+d+{i}', lambda i=i: self.paste_from_history(i-1))except Exception as e:print(f"注册快捷键失败: {e}")def unregister_hotkeys(self):"""取消注册全局快捷键"""try:keyboard.unhook_all_hotkeys()except Exception as e:print(f"取消注册快捷键失败: {e}")def toggle_hotkeys(self, state):"""切换快捷键启用状态"""self.hotkeys_enabled = state == Qt.Checkedif self.hotkeys_enabled:self.register_hotkeys()else:self.unregister_hotkeys()def toggle_auto_paste(self, state):"""切换自动粘贴设置"""self.auto_paste = state == Qt.Checkeddef toggle_start_with_system(self, state):"""切换开机启动设置"""self.start_with_system = state == Qt.Checked# 这里需要实现实际的开机启动设置逻辑QMessageBox.information(self, "提示", "开机启动功能需要根据操作系统进行额外配置")def update_history_limit(self, value):"""更新历史记录最大数量"""self.max_history = value# 如果当前历史记录超过新限制,截断if len(self.history) > self.max_history:self.history = self.history[:self.max_history]self.update_history_list()def change_theme(self, theme_name):"""更改应用程序主题"""if theme_name == "默认":self.setStyleSheet("")elif theme_name == "深色":self.set_dark_theme()elif theme_name == "蓝色":self.set_blue_theme()elif theme_name == "绿色":self.set_green_theme()elif theme_name == "粉色":self.set_pink_theme()def set_dark_theme(self):"""设置深色主题"""dark_style = """QMainWindow {background-color: #333;}QListWidget {background-color: #444;color: #eee;border: 1px solid #555;}QListWidget::item {border-bottom: 1px solid #555;}QListWidget::item:hover {background-color: #555;}QListWidget::item:selected {background-color: #4CAF50;}QTextEdit, QLineEdit {background-color: #444;color: #eee;border: 1px solid #555;}QPushButton {background-color: #555;color: white;border: none;}QPushButton:hover {background-color: #666;}QLabel {color: #eee;}QSpinBox, QComboBox {background-color: #444;color: #eee;border: 1px solid #555;}"""self.setStyleSheet(dark_style)def set_blue_theme(self):"""设置蓝色主题"""blue_style = """QMainWindow {background-color: #e6f2ff;}QListWidget {background-color: #f0f7ff;border: 1px solid #b3d1ff;}QListWidget::item:hover {background-color: #d9e6ff;}QListWidget::item:selected {background-color: #4d94ff;color: white;}QPushButton {background-color: #4d94ff;color: white;}QPushButton:hover {background-color: #3d84ef;}"""self.setStyleSheet(blue_style)def set_green_theme(self):"""设置绿色主题"""green_style = """QMainWindow {background-color: #e6ffe6;}QListWidget {background-color: #f0fff0;border: 1px solid #b3e6b3;}QListWidget::item:hover {background-color: #d9ffd9;}QListWidget::item:selected {background-color: #4CAF50;color: white;}QPushButton {background-color: #4CAF50;color: white;}QPushButton:hover {background-color: #45a049;}"""self.setStyleSheet(green_style)def set_pink_theme(self):"""设置粉色主题"""pink_style = """QMainWindow {background-color: #ffe6f2;}QListWidget {background-color: #fff0f7;border: 1px solid #ffb3d9;}QListWidget::item:hover {background-color: #ffd9ec;}QListWidget::item:selected {background-color: #ff66b3;color: white;}QPushButton {background-color: #ff66b3;color: white;}QPushButton:hover {background-color: #ff4da6;}"""self.setStyleSheet(pink_style)def check_clipboard(self):"""检查剪贴板内容是否变化"""current_clipboard = pyperclip.paste()if current_clipboard and (not self.history or current_clipboard != self.history[0]['content']):# 添加到历史记录self.add_to_history(current_clipboard)def add_to_history(self, content):"""添加内容到历史记录"""if not content.strip():return# 如果内容与上一条相同,不重复添加if self.history and content == self.history[0]['content']:return# 创建新的历史记录项history_item = {'content': content,'timestamp': datetime.now().strftime("%Y-%m-%d %H:%M:%S"),'preview': content[:50] + ("..." if len(content) > 50 else "")}# 添加到历史记录开头self.history.insert(0, history_item)# 如果超过最大限制,移除最旧的记录if len(self.history) > self.max_history:self.history = self.history[:self.max_history]# 更新UIself.update_history_list()# 保存历史记录self.save_history()def update_history_list(self):"""更新历史记录列表显示"""self.history_list.clear()# 定义不同颜色colors = [QColor("#FF0000"), # 红色QColor("#00AA00"), # 绿色QColor("#0000FF"), # 蓝色QColor("#AA00AA"), # 紫色QColor("#00AAAA"), # 青色QColor("#AA5500"), # 棕色QColor("#FF00FF"), # 粉红QColor("#555555"), # 深灰QColor("#0055FF") # 天蓝]for i, item in enumerate(self.history):list_item = QListWidgetItem(f"[{i+1}] {item['timestamp']} - {item['preview']}")# 为前9项设置不同颜色if i < 9:list_item.setForeground(QBrush(colors[i % len(colors)]))self.history_list.addItem(list_item)def show_selected_item(self, item):"""显示选中项的详细信息"""index = self.history_list.row(item)if 0 <= index < len(self.history):selected_item = self.history[index]self.detail_text.setPlainText(selected_item['content'])def copy_selected(self):"""复制选中项到剪贴板"""selected_items = self.history_list.selectedItems()if selected_items:index = self.history_list.row(selected_items[0])if 0 <= index < len(self.history):pyperclip.copy(self.history[index]['content'])self.tray_icon.showMessage("剪贴板历史管理器","内容已复制到剪贴板",QSystemTrayIcon.Information,1000)def paste_selected(self):"""粘贴选中项"""self.copy_selected()# 模拟Ctrl+V粘贴if self.auto_paste:keyboard.send('ctrl+v')def paste_from_history(self, index):"""通过快捷键粘贴指定索引的历史记录"""if 0 <= index < len(self.history):# 高亮显示对应的项if index < self.history_list.count():self.history_list.setCurrentRow(index)self.history_list.scrollToItem(self.history_list.currentItem())pyperclip.copy(self.history[index]['content'])if self.auto_paste:keyboard.send('ctrl+v')def delete_selected(self):"""删除选中项"""selected_items = self.history_list.selectedItems()if selected_items:index = self.history_list.row(selected_items[0])if 0 <= index < len(self.history):# 确认对话框reply = QMessageBox.question(self, '确认删除','确定要删除这条记录吗?',QMessageBox.Yes | QMessageBox.No,QMessageBox.No)if reply == QMessageBox.Yes:del self.history[index]self.update_history_list()self.detail_text.clear()self.save_history()def clear_history(self):"""清空所有历史记录"""if not self.history:return# 确认对话框reply = QMessageBox.question(self, '确认清空','确定要清空所有历史记录吗?此操作不可撤销!',QMessageBox.Yes | QMessageBox.No,QMessageBox.No)if reply == QMessageBox.Yes:self.history = []self.update_history_list()self.detail_text.clear()self.save_history()def search_history(self):"""搜索历史记录"""search_text = self.search_input.text().lower()if not search_text:self.update_history_list()returnself.history_list.clear()# 定义不同颜色colors = [QColor("#FF0000"), # 红色QColor("#00AA00"), # 绿色QColor("#0000FF"), # 蓝色QColor("#AA00AA"), # 紫色QColor("#00AAAA"), # 青色QColor("#AA5500"), # 棕色QColor("#FF00FF"), # 粉红QColor("#555555"), # 深灰QColor("#0055FF") # 天蓝]for i, item in enumerate(self.history):if search_text in item['content'].lower():list_item = QListWidgetItem(f"[{i+1}] {item['timestamp']} - {item['preview']}")# 保持颜色效果if i < 9:list_item.setForeground(QBrush(colors[i % len(colors)]))self.history_list.addItem(list_item)def save_history(self):"""保存历史记录到文件"""try:with open(self.history_file, 'w', encoding='utf-8') as f:json.dump(self.history, f, ensure_ascii=False, indent=2)except Exception as e:print(f"保存历史记录失败: {e}")def load_history(self):"""从文件加载历史记录"""try:if os.path.exists(self.history_file):with open(self.history_file, 'r', encoding='utf-8') as f:self.history = json.load(f)except Exception as e:print(f"加载历史记录失败: {e}")def quit_app(self):"""退出应用程序"""self.save_history()self.tray_icon.hide()QApplication.quit()if __name__ == "__main__":app = QApplication(sys.argv)# 设置应用程序图标app_icon = QIcon()app_icon.addFile('icon16.png', QSize(16, 16))app_icon.addFile('icon32.png', QSize(32, 32))app_icon.addFile('icon48.png', QSize(48, 48))app_icon.addFile('icon256.png', QSize(256, 256))app.setWindowIcon(app_icon)window = ClipboardHistoryApp()window.show()sys.exit(app.exec_())
七、总结与扩展
7.1 项目总结
本文实现了一个功能完善的剪贴板历史管理工具,具有以下优点:
- 跨平台:基于Python,可在Windows/macOS/Linux运行
- 高性能:使用定时器检查剪贴板,资源占用低
- 易用性:直观的GUI界面和快捷键操作
- 可扩展:代码结构清晰,便于添加新功能
7.2 可能的改进方向
- 分类标签:为历史记录添加标签分类功能
- 图片支持:扩展支持图片剪贴板历史
- 云同步:实现历史记录多设备同步
- 插件系统:支持通过插件扩展功能
- OCR集成:对图片中的文字进行识别保存
7.3 实际应用价值
经过测试,使用这个工具可以:
- 减少30%以上的重复复制操作
- 提高代码片段复用率
- 避免因剪贴板覆盖导致的内容丢失
- 快速获取之前复制过的常用内容(如密码、命令等)
希望这个项目能帮助你提升工作效率!如果有任何问题或建议,欢迎在评论区留言讨论。
附录:常见问题解答
Q: 如何设置开机启动?
A: 需要根据操作系统添加启动项,Windows可将其添加到"启动"文件夹或修改注册表。
Q: 快捷键冲突怎么办?
A: 可以在代码中修改keyboard.add_hotkey
的参数使用其他组合键。
Q: 历史记录文件在哪里?
A: 默认保存在程序同级目录下的clipboard_history.json
文件中。
Q: 支持图片或富文本吗?
A: 当前版本仅支持纯文本,后续可扩展支持更多格式。
相关文章:
【开源】Python打造高效剪贴板历史管理器:实现跨平台生产力工具
📋【开源】Python打造高效剪贴板历史管理器:实现跨平台生产力工具 🌈 个人主页:创客白泽 - CSDN博客 🔥 系列专栏:🐍《Python开源项目实战》 💡 热爱不止于代码,热情源自…...
Day 14 训练
Day 14 训练 SHAP(SHapley Additive exPlanations)1.创建解释器2.将特征贡献可视化第一部分:绘制SHAP特征重要性条形图第二部分:绘制SHAP特征重要性蜂巢图 SHAP(SHapley Additive exPlanations) 旨在解释复…...
V型球阀材质性能深度解析:专攻颗粒、料浆与高腐蚀介质的工业利器-耀圣
V型球阀材质性能深度解析:专攻颗粒、料浆与高腐蚀介质的工业利器 在工业流体控制领域,V型球阀凭借其独特的V型切口设计与多元化材质适配能力,成为含颗粒、纤维、料浆及强腐蚀性介质的“终极克星”。本文从材质性能与驱动适配性两大维度切入&…...
缓存套餐-01.Spring Cache入门案例
一.导入案例代码 application.yml server:port: 8888 spring:datasource:druid:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/spring_cache_demo?serverTimezoneAsia/Shanghai&useUnicodetrue&characterEncodingutf-8&zeroDat…...
2025年APP安全攻防指南:抵御DDoS与CC攻击的实战策略
2025年,随着AI技术与物联网设备的深度渗透,DDoS与CC攻击的复杂性和破坏性显著升级。攻击者通过伪造用户行为、劫持智能设备、利用协议漏洞等手段,对APP发起精准打击,导致服务瘫痪、用户流失甚至数据泄露。面对这一挑战,…...
力扣:多数元素
题目 给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。 你可以假设数组是非空的,并且给定的数组总是存在多数元素。 示例 示例 1: 输入:nums [3,2,3] 输出ÿ…...
2025年小程序DDoS与CC攻击防御全指南:构建智能安全生态
2025年,小程序已成为企业数字化转型的核心载体,但随之而来的DDoS与CC攻击也愈发复杂化、智能化。攻击者利用AI伪造用户行为、劫持物联网设备发起T级流量冲击,甚至通过漏洞窃取敏感数据。如何在高并发业务场景下保障小程序的稳定与安全&#x…...
【Python】PDF文件处理(PyPDF2、borb、fitz)
Python提供了多种方法和库用于处理PDF文件,这些工具可以帮助开发者实现诸如读取、写入、合并、拆分以及压缩等功能。以下是几个常用的Python PDF操作库及其基本用法(PyPDF2、borb、fitz)。 1. PyPDF2 PyPDF2 是一个功能强大的库࿰…...
Web 架构之前后端分离
文章目录 思维导图一、引言二、前后端分离的概念代码示例(简单的前后端分离交互)后端(使用 Python Flask 框架)前端(使用 JavaScript 和 jQuery) 三、前后端分离的优势3.1 提高开发效率3.2 代码可维护性增强…...
Pycharm安装后打开提示:此应用无法在你的电脑上运行,若要找到合适于你的电脑的版本,请咨询发布者
问题描述 今天下载安装好社区版的pycharm之后双击运行出现提示:此应用无法在你的电脑上运行,若要找到合适于你的电脑的版本,请咨询发布者。 首先我们需要查看Windows如何查看系统是ARM64还是X64架构 在 cmd 命令窗中输入 systeminfo 即可&a…...
正则表达式实战指南:原理、口诀与高频场景案例
正则表达式实战指南:原理、口诀与高频场景案例 正则表达式(Regular Expression)是程序员处理文本的瑞士军刀,被广泛应用于数据验证、日志分析、爬虫开发等领域。本文将从原理讲解、口诀速查到高频实战案例,带你系统掌…...
Spark缓存--persist方法
1. 功能本质 persist:这是一个通用的持久化方法,能够指定多种不同的存储级别。存储级别决定了数据的存储位置(如内存、磁盘)以及存储形式(如是否序列化)。 2. 存储级别指定 persist:可以通过传入…...
【LeetCode 热题 100】二叉树 系列
📁 104. 二叉树的最大深度 深度就是树的高度,即只要左右子树其中有一个不为空,就继续往下递归,知道节点为空,向上返回。 int maxDepth(TreeNode* root) {if(root nullptr)return 0;return max(maxDepth(root->lef…...
CTF之常见的文件头和文件尾
1、图片 JPEG 文件头:FF D8 FF 文件尾:FF D9TGA 未压缩的前4字节 00 00 02 00 RLE压缩的前5字节 00 00 10 00 00PNG 文件头:89 50 4E 47 0D 0A 1A 0A 文件尾:AE 42 60 82GIF 文件头:47 49 46 38 39(37) 61 文件尾&…...
软件设计师教程——第一章 计算机系统知识(上)
前言 在竞争激烈的就业市场中,证书是大学生求职的重要加分项。中级软件设计师证书专业性强、认可度高,是计算机相关专业学生考证的热门选择,既能检验专业知识,又有助于职业发展。本教程将聚焦核心重点,以点带面构建知…...
KRaft (Kafka 4.0) 集群配置指南(超简单,脱离 ZooKeeper 集群)还包含了简化测试指令的脚本!!!
docker-compose方式部署kafka集群 Kafka 4.0 引入了 KRaft 模式(Kafka Raft Metadata Mode),它使 Kafka 集群不再依赖 ZooKeeper 进行元数据管理。KRaft 模式简化了 Kafka 部署和管理,不需要额外配置 ZooKeeper 服务,…...
安全月演讲比赛活动讲话稿
同志们:在公司上下万众一心创建“无违章企业”的大形势下,由公司工会、团委举办的“安全与我”演讲比赛,经过紧张激烈的预赛,今天进行正式决赛。 从预赛的38名选手中脱颖而出的10名选手,今天将再次登台献技,…...
实时操作系统:航空电子系统的安全基石还是创新枷锁?
引言:航空电子系统的进化论 在航空电子技术的漫长发展历程中,飞行器控制系统实现从机械仪表到数字计算机的跨越,这一进步具有深远意义。现代战机以超过 2 马赫的速度突破音障,无人机群在复杂电磁环境下完成自主编队,这…...
windows 部署 Kafka3.x KRaft 模式 不依赖 ZooKeeper
1.下载 https://archive.apache.org/dist/kafka/3.9.0/kafka_2.12-3.9.0.tgz2.配置使用 KRaft 模式 2.1 修改 Kafka 的配置文件 cd D:\data\bigdata\kafka_2.12-3.9.0\config\kraft 修改 server.properties # 设置 Kafka 数据日志存储目录 log.dirsD:\\data\\bigdata\\kaf…...
SEMI E40-0200 STANDARD FOR PROCESSING MANAGEMENT(加工管理标准)-(一)
1 目的 物料(例如晶圆)加工在设备中的自动化管理与控制是实现工厂自动化的关键要素。本标准针对半导体制造环境中与设备内部物料处理相关的通信需求进行了规范。本标准规定了在加工单元接收到的指定材料所应适用的加工方法(例如Etch腔室需要Run哪支Recipe)。它阐述了物料加工的…...
Web 架构之高可用基础
文章目录 引言一、无状态服务设计(Session 托管至 Redis 集群)1. 概念与原理2. 代码示例(Python Flask 应用)3. 常见问题及解决办法 二、数据库读写分离(MySQL 主从 ProxySQL 流量分发)1. 概念与原理2. 配…...
巧用python之--模仿PLC(PLC模拟器)
工作中用到了VM(VisionMaster4.3)有时候需要和PLC打交道,但是PLC毕竟是别人的,不方便修改别人的程序,这时候需要一个灵活的PLC模拟器是多么好呀! 先说背景: PLC型号 汇川Easy521: Modbus TCP 192.168.1.10:502 在汇川Easy521中Modbus保持寄存器D寄存器 ,在modbus协议中 0-4区…...
Nginx +Nginx-http-flv-module 推流拉流
这两天为了利用云服务器实现 Nginx 进行OBS Rtmp推流,Flv拉流时发生了诸多情况,记录实现过程。 环境 OS:阿里云CentOS 7.9 64位Nginx:nginx-1.28.0Nginx-http-flv-module:nginx-http-flv-module-1.2.12 安装Nginx编…...
DRF+Vue项目线上部署:腾讯云+Centos7.6
1.服务器选购和配置 1.1.服务器选购 1.2.防火墙/安全组配置 80是HTTP的端口,443是HTTPS的端口,22是远程连接的端口,3306是mysql的端口。 1.3.远程连接软件(tabby)配置 下载:https://github.com/Eugeny/ta…...
大疆无人机(全系列,包括mini)拉流至电脑,实现直播
参考视频 【保姆级教程】大疆无人机rtmp推流直播教程_哔哩哔哩_bilibili VLC使用教程: VLC工具使用指南-CSDN博客 目录 实现效果: 电脑端 编辑 编辑 无人机端 VLC拉流 分析 实现效果: (实验机型:大疆mini4kRC-N2遥控器、大…...
Spring普通配置类 vs 自动配置类-笔记
1.简要版 Configuration和Bean,既可以用于普通配置类,也可以用于自动配置类。二者的区别和联系是什么呢? 区别: Configuration和Bean是Spring框架本身的注解,用于定义配置类和生成Bean。而自动配置通常是Spring Boo…...
解决Ceph 14.2.22 Nautilus版本监视器慢操作问题的实践指南
解决Ceph Nautilus版本监视器慢操作问题的实践指南 问题背景问题现象问题分析1. 确认监视器状态2. 检查慢操作详情3. 深入分析操作状态 问题原因解决方案立即解决方法 总结 在生产环境中执行任何操作前,请确保已备份重要数据,并在测试环境中验证解决方案…...
Go使用Gin写一个对MySQL的增删改查服务
首先用SQL创建一个包含id、name属性的users表 create table users (id int auto_incrementprimary key,name varchar(255) null );查询所有用户信息: func queryData(db *sql.DB, w http.ResponseWriter) {rows, err : db.Query("SELECT * FROM users"…...
数字孪生医疗:构建患者特异性数字孪生体路径探析
引言 数字孪生技术正逐渐成为医疗健康领域的一场革命性力量,它通过创建人体器官和系统的数字复制品,为疾病预测、诊断和个性化治疗开辟了前所未有的可能性。在心血管疾病领域,数字孪生技术的应用尤为引人注目,特别是对于扩张型心肌病(Dilated Cardiomyopathy,DCM)这一常…...
rust程序静态编译的两种方法总结
1. 概述 经过我的探索,总结了两种rust程序静态编译的方法,理论上两种方法都适用于windows、mac os和linux(mac os未验证),实测方法一性能比方法二好,现总结如下,希望能够帮到你. 2.方法一 2.1 添加配置文件 在项目的同级文件夹下新…...
threejs 添加css3d标签 vue3
如图所示,给收费站标注标签。步骤如下: 一、引入 import {CSS3DRenderer,CSS3DObject, } from "three/examples/jsm/renderers/CSS3DRenderer"; 二、 //一、申明css3渲染器 const label3DRenderer ref()//二、创建css3d渲染器--将渲染器加…...
【git】git fsmonitor
git fsmonitor 是 Git 提供的一个特性,用于提高 Git 的性能,尤其是在处理文件状态检查(git status)时。它通过文件系统监控服务(如 Windows 上的 FileSystemWatcher 或 Linux 上的 inotify)来跟踪文件系统的…...
开源照片管理系统PhotoPrism的容器化部署与远程管理配置
文章目录 前言1.关于PhotoPrism2.本地部署PhotoPrism3.PhotoPrism简单使用4. 安装内网穿透5.配置PhotoPrism公网地址6. 配置固定公网地址 前言 你是不是用手机拍照片的时候无所谓拍了多少张,但在整理的时候却要占用超多时间?别怕,今天给大家…...
macOS Python 环境配置指南
1. 检查现有 Python 环境 python3 --version # 检查 Python 3 版本 pip3 --version # 检查 pip 版本 2. 安装 pyenv(Python 版本管理工具) # 使用 Homebrew 安装 pyenvbrew install pyenv# 配置 pyenv 环境变量(添加到 ~/.zshrc&#…...
如何阅读、学习 Git 核心源代码 ?
学习 Git 核心源代码是一个深入理解版本控制系统底层原理的绝佳方式。以下是分阶段的系统性建议,结合了实践经验和学习路径设计: 一、前置知识储备 C语言进阶 重点掌握指针操作(尤其是二级指针和函数指针)结构体嵌套与内存对齐…...
学习黑客 MAC 地址深入了解
在江湖之中,每位少侠既有“门派”加身,也需持有“令牌”通行。MAC地址便是我被师门铁订在骨血里的“先天武功心法”,铸于出厂之时,终身不变,只有破阵高手才能暗度陈仓才能改写;而IP地址则是我行走江湖的“后…...
长事务:数据库中的“隐形炸弹“——金仓数据库运维避坑指南
引言:凌晨三点的告警 "张工!生产库又告警了!"凌晨三点的电话铃声总是格外刺耳。运维团队发现数据库频繁进入单用户模式,排查发现某核心表的年龄值(Age)已突破20亿大关。经过一夜奋战,…...
WTK6900C-48L:离线语音芯片重构玩具DNA,从“按键操控”到“声控陪伴”的交互跃迁
一:开发背景 随着消费升级和AI技术进步,传统玩具的机械式互动已难以满足市场需求。语音控制芯片的引入使玩具实现了从被动玩耍到智能交互的跨越式发展。通过集成高性价比的语音识别芯片,现代智能玩具不仅能精准响应儿童指令,还能实…...
一文读懂Python之requests模块(36)
一、requests模块简介 requests模块是python中原生的一款基于网络请求的模块,功能强大,简单便捷且高效 ,该模块可以模拟浏览器发送请求,主要包括指定url、发起请求、获取响应数据和持久化存储,包括 GET、POST、PUT、…...
Java 异常
Java 异常的体系结构 java.lang.Throwable ├── Error(严重错误,程序无法处理) │ ├── OutOfMemoryError │ ├── StackOverflowError │ └── ... └── Exception(程序可以处理的异常)├── Check…...
智能外呼机器人的核心优势
随着人工智能技术的快速发展,智能外呼机器人已成为企业降本增效的重要工具。其通过整合语音识别(ASR)、自然语言处理(NLP)、语音合成(TTS)等技术,不仅替代了大量重复性人工劳动&…...
n8n - 开放灵活的智能自动化工作流平台
n8n - 开放灵活的智能自动化工作流平台 在当今数字化转型的大潮中,自动化已成为众多企业提升效率、优化流程的关键手段。而在众多自动化工具中,n8n以其开放灵活且强大的功能脱颖而出,成为技术团队的可靠选择。今天,我们将深入了解n8n这个开源自动化工作流平台,探索其广泛…...
window 显示驱动开发-处理内存段(二)
KMD 不需要在其内存段中指定 GPU 可用的所有视频内存资源。 但是,KMD 必须指定 VidMm 在系统上运行的所有进程中管理的所有内存资源。 例如: 实现固定函数管道的顶点着色器微代码可以驻留在 GPU 地址空间中,但在 VidMm 管理的内存之外&#x…...
RSS 2025|斯坦福提出「统一视频行动模型UVA」:实现机器人高精度动作推理
导读 在机器人领域,让机器人像人类一样理解视觉信息并做出精准行动,一直是科研人员努力的方向。今天,我们要探讨的统一视频行动模型(Unified Video Action Model,UVA),就像给机器人装上了一个“…...
代码随想录算法训练营第60期第三十天打卡
大家好,今天我们要走进一个全新的章节,这一章叫做贪心算法,前面我们讲的是回溯算法,那究竟什么是贪心算法呢?我们一起走进今天的内容。 第一部分贪心的理论基础 其实大家看这个名字估计也会有一定了解,贪心…...
腾讯云:数字世界的“量子熔炉”与硅基文明引擎
一、算力拓扑学:重新定义空间的计算密度 腾讯云的算力网络正在突破经典物理限制,其分布式架构通过“量子化”资源调度实现超维计算: 虚拟化跃迁:基于KVM的轻量级虚拟化技术,将单台物理服务器切割为百…...
Python Cookbook-7.7 通过 shelve 修改对象
任务 你正在使用标准库模块shelve。你用shelve处理过的一些值是易变的对象(mutableobjects),而且你需要修改这些对象。 解决方案 shelve 模块提供了一种持久的字典——在强大的关系型数据库和简洁的 marshal、pickledbm 以及类似的文件格式之间,它有着…...
Baklib构建AI就绪知识管理体系
Baklib构建AI就绪知识体系 在数字化转型加速的背景下,Baklib通过其AI就绪知识管理体系,为企业提供了从数据整合到智能应用的完整解决方案。该平台以知识中台为核心架构,依托自然语言处理与机器学习技术,对分散在企业文档系统、协…...
嵌入式开发学习日志Day16
一、指针函数 函数的返回值为指针的函数; 注意:不能返回局部变量的地址; 可以返回静态变量的地址; 可以返回全局变量的地址; 1、动态内存分配 void *malloc(size_t size); //申请空间的函数 void free(*ptr); …...
SLAM文献之KernelGPA: A Globally Optimal Solution to Deformable SLAM in Closed-form
KernelGPA: A Globally Optimal Solution to Deformable SLAM in Closed-form 提出了一种在非刚性变形环境下求解 SLAM 问题的闭式全局最优解方法。下面是对其算法原理和核心推导过程的系统解析。 一、算法背景与目标 问题描述: 传统 SLAM 主要假设环境为刚性&am…...