【Python开源】深度解析:一款高效音频封面批量删除工具的设计与实现
🎵 【Python开源】深度解析:一款高效音频封面批量删除工具的设计与实现
🌈 个人主页:创客白泽 - CSDN博客
🔥 系列专栏:🐍《Python开源项目实战》
💡 热爱不止于代码,热情源自每一个灵感闪现的夜晚。愿以开源之火,点亮前行之路。
👍 如果觉得这篇文章有帮助,欢迎您一键三连,分享给更多人哦
📖 概述
在数字音乐管理过程中,音频文件内嵌的封面图片往往会占用额外存储空间,特别是当我们需要批量处理大量音频文件时。本文介绍一款基于Python和PyQt5开发的跨平台音频封面删除工具,它支持多种音频格式(MP3、FLAC、M4A、OGG、WMA),提供三种不同的处理方式,并具备友好的图形用户界面。
本工具不仅能有效移除音频文件中的封面数据,还能保持音频质量无损,是音乐收藏家和数字资产管理者的实用工具。下面我们将从功能、实现原理、代码解析等多个维度进行详细介绍。
🛠️ 功能特点
-
多格式支持:
- MP3 (ID3标签)
- FLAC (Vorbis注释)
- M4A/MP4 (iTunes元数据)
- OGG (Vorbis/Opus)
- WMA (ASF容器)
-
三种处理方式:
- Mutagen库(推荐):Python专用音频元数据处理库
- FFmpeg:专业音视频处理工具
- 二进制处理:最后手段的直接文件操作
-
智能文件管理:
- 拖放文件夹支持
- 自动扫描子目录
- 可选输出目录设置
- 文件类型过滤
-
可视化操作:
- 进度条显示
- 处理结果统计
- 错误处理机制
🖼️ 界面展示
图1:软件主界面,包含目录设置、文件列表和操作按钮
图2、图3:文件处理进度显示
🧰 使用说明
1. 准备工作
- 安装Python 3.7+
- 安装依赖库:
pip install PyQt5 mutagen
- (可选) 如需使用FFmpeg方式,需提前安装FFmpeg并加入系统PATH
2. 操作步骤
- 选择输入目录:点击"浏览"按钮或直接拖放文件夹到输入框
- 设置输出目录(可选):默认为输入目录下的"cleaned_audio"文件夹
- 选择处理方式:
- Mutagen:推荐方式,处理速度快且稳定
- FFmpeg:适合复杂音频文件
- 二进制:最后手段,兼容性较差
- 扫描文件:点击"扫描文件"按钮获取目录下所有支持的音频文件
- 选择处理范围:
- “处理选中”:仅处理列表中选中的文件
- “处理全部”:批量处理所有扫描到的文件
- 查看结果:处理完成后会显示成功/失败统计,处理后的文件保存在输出目录
3. 注意事项
- 处理前建议备份原始文件
- 某些音频播放器可能需要重新扫描文件才能显示更改
- FLAC文件的封面删除会同时移除所有内嵌图片
💻 代码深度解析
1. 核心技术栈
- PyQt5:构建现代化GUI界面
- Mutagen:音频元数据处理核心库
- FFmpeg(可选):专业音视频处理
- 标准库:os, sys, shutil等处理文件操作
2. 关键类说明
DraggableLineEdit (自定义拖放文本框)
class DraggableLineEdit(QLineEdit):def dragEnterEvent(self, event):if event.mimeData().hasUrls():event.acceptProposedAction()def dropEvent(self, event):for url in event.mimeData().urls():path = url.toLocalFile()if os.path.isdir(path):self.setText(path)break
实现文件夹拖放功能的核心代码,增强了用户体验
AudioCoverRemover (主窗口类)
def process_with_mutagen(self, input_path, output_path, ext):# 先复制文件if input_path != output_path:shutil.copy2(input_path, output_path)# 根据格式使用不同的处理方法if ext == "mp3":audio = MP3(output_path, ID3=ID3)if audio.tags:audio.tags.delall("APIC")audio.save()elif ext == "flac":audio = FLAC(output_path)if audio.pictures:audio.clear_pictures()audio.save()...
不同音频格式的封面删除逻辑,展示了Mutagen库的强大灵活性
3. 设计亮点
- 多方法兼容处理:
- 提供三种不同实现方式,确保最大兼容性
- 自动选择最适合当前文件的方法
- 现代化UI设计:
- 自定义样式表美化界面
- 响应式布局适应不同分辨率
- 进度反馈增强用户体验
- 健壮的错误处理:
- 捕获并记录各种处理异常
- 不影响整体批处理流程
- 跨平台支持:
- 兼容Windows/macOS/Linux
- 自动处理路径分隔符差异
📥 源码下载
import os
import sys
import subprocess
import shutil
from mutagen.mp3 import MP3
from mutagen.id3 import ID3, APIC
from mutagen.flac import FLAC
from mutagen.mp4 import MP4
from mutagen.oggopus import OggOpus
from mutagen.oggvorbis import OggVorbis
from mutagen.asf import ASF
from PyQt5.QtWidgets import (QApplication, QMainWindow, QVBoxLayout, QHBoxLayout,QPushButton, QLabel, QLineEdit, QFileDialog,QListWidget, QWidget, QProgressBar, QMessageBox,QCheckBox, QGroupBox, QComboBox)
from PyQt5.QtCore import Qt, QMimeData
from PyQt5.QtGui import QColor, QPalette, QIconclass DraggableLineEdit(QLineEdit):def __init__(self, parent=None):super().__init__(parent)self.setAcceptDrops(True)def dragEnterEvent(self, event):if event.mimeData().hasUrls():event.acceptProposedAction()def dropEvent(self, event):for url in event.mimeData().urls():path = url.toLocalFile()if os.path.isdir(path):self.setText(path)breakclass AudioCoverRemover(QMainWindow):def __init__(self):super().__init__()self.setWindowTitle("🎵 音频封面删除工具")self.setGeometry(100, 100, 547, 608)# 支持的音频格式self.supported_formats = {'mp3': 'MP3音频','flac': 'FLAC无损音频','m4a': 'MP4/AAC音频','ogg': 'OGG音频','wma': 'WMA音频'}# 初始化变量self.audio_files = []self.current_method = "mutagen"# 设置UI样式self.setup_ui_style()# 初始化UIself.init_ui()# 设置窗口图标self.setWindowIcon(QIcon(self.get_icon_path()))def get_icon_path(self):"""获取图标路径(适配不同平台)"""if getattr(sys, 'frozen', False):# 打包后的路径base_path = sys._MEIPASSelse:# 开发时的路径base_path = os.path.dirname(os.path.abspath(__file__))return os.path.join(base_path, 'icon.png')def setup_ui_style(self):"""设置现代化UI样式"""palette = self.palette()palette.setColor(QPalette.Window, QColor(245, 245, 245))palette.setColor(QPalette.WindowText, QColor(60, 60, 60))palette.setColor(QPalette.Base, QColor(255, 255, 255))palette.setColor(QPalette.AlternateBase, QColor(240, 240, 240))palette.setColor(QPalette.ToolTipBase, QColor(255, 255, 220))palette.setColor(QPalette.ToolTipText, Qt.black)palette.setColor(QPalette.Text, Qt.black)palette.setColor(QPalette.Button, QColor(70, 160, 230))palette.setColor(QPalette.ButtonText, Qt.white)palette.setColor(QPalette.BrightText, Qt.red)palette.setColor(QPalette.Highlight, QColor(70, 160, 230))palette.setColor(QPalette.HighlightedText, Qt.white)self.setPalette(palette)self.setStyleSheet("""QGroupBox {border: 1px solid #dcdcdc;border-radius: 6px;margin-top: 12px;padding-top: 18px;font-weight: bold;color: #505050;}QGroupBox::title {subcontrol-origin: margin;left: 12px;padding: 0 5px;}QPushButton {background-color: #46a0f0;color: white;border: none;padding: 7px 14px;border-radius: 5px;min-width: 90px;font-size: 13px;}QPushButton:hover {background-color: #3a8cd0;}QPushButton:pressed {background-color: #2e78b0;}QPushButton:disabled {background-color: #cccccc;color: #888888;}QListWidget {border: 1px solid #dcdcdc;border-radius: 5px;background: white;font-size: 13px;}QProgressBar {border: 1px solid #dcdcdc;border-radius: 5px;text-align: center;height: 20px;font-size: 12px;}QProgressBar::chunk {background-color: #46a0f0;border-radius: 4px;}QComboBox {border: 1px solid #dcdcdc;border-radius: 4px;padding: 3px;min-width: 120px;}QLineEdit {border: 1px solid #dcdcdc;border-radius: 4px;padding: 5px;}""")def init_ui(self):main_widget = QWidget()self.setCentralWidget(main_widget)layout = QVBoxLayout()layout.setContentsMargins(12, 12, 12, 12)layout.setSpacing(10)# 顶部控制区域top_layout = QHBoxLayout()# 方法选择method_layout = QHBoxLayout()method_layout.addWidget(QLabel("处理方法:"))self.method_combo = QComboBox()self.method_combo.addItems(["Mutagen (推荐)", "FFmpeg", "二进制处理"])method_layout.addWidget(self.method_combo)# 格式过滤format_layout = QHBoxLayout()format_layout.addWidget(QLabel("文件类型:"))self.format_combo = QComboBox()self.format_combo.addItems(["所有支持格式"] + list(self.supported_formats.values()))format_layout.addWidget(self.format_combo)top_layout.addLayout(method_layout)top_layout.addStretch()top_layout.addLayout(format_layout)# 目录设置dir_group = QGroupBox("目录设置")dir_layout = QVBoxLayout()dir_layout.setSpacing(10)# 输入目录(使用自定义的可拖放QLineEdit)input_layout = QHBoxLayout()input_layout.addWidget(QLabel("输入目录:"))self.input_path = DraggableLineEdit()self.input_path.setPlaceholderText("拖放文件夹到这里或点击浏览...")self.browse_input_btn = QPushButton("浏览")self.browse_input_btn.clicked.connect(self.browse_input)input_layout.addWidget(self.input_path, stretch=1)input_layout.addWidget(self.browse_input_btn)# 输出目录output_layout = QHBoxLayout()output_layout.addWidget(QLabel("输出目录:"))self.output_path = DraggableLineEdit()self.output_path.setPlaceholderText("默认: 输入目录下的'cleaned_audio'文件夹")self.browse_output_btn = QPushButton("浏览")self.browse_output_btn.clicked.connect(self.browse_output)output_layout.addWidget(self.output_path, stretch=1)output_layout.addWidget(self.browse_output_btn)dir_layout.addLayout(input_layout)dir_layout.addLayout(output_layout)dir_group.setLayout(dir_layout)# 文件列表self.file_list = QListWidget()self.file_list.setSelectionMode(QListWidget.MultiSelection)self.file_list.setMinimumHeight(250)# 进度条self.progress = QProgressBar()self.progress.setVisible(False)# 操作按钮btn_layout = QHBoxLayout()self.scan_btn = QPushButton("🔍 扫描文件")self.scan_btn.clicked.connect(self.scan_files)self.process_btn = QPushButton("⚡ 处理选中")self.process_btn.clicked.connect(self.process_selected)self.process_btn.setEnabled(False)self.process_all_btn = QPushButton("🚀 处理全部")self.process_all_btn.clicked.connect(self.process_all)self.process_all_btn.setEnabled(False)btn_layout.addWidget(self.scan_btn)btn_layout.addWidget(self.process_btn)btn_layout.addWidget(self.process_all_btn)# 添加到主布局layout.addLayout(top_layout)layout.addWidget(dir_group)layout.addWidget(self.file_list)layout.addWidget(self.progress)layout.addLayout(btn_layout)main_widget.setLayout(layout)self.update_buttons()def browse_input(self):path = QFileDialog.getExistingDirectory(self, "选择输入目录")if path:self.input_path.setText(path)def browse_output(self):path = QFileDialog.getExistingDirectory(self, "选择输出目录")if path:self.output_path.setText(path)def scan_files(self):input_dir = self.input_path.text()if not os.path.isdir(input_dir):QMessageBox.warning(self, "错误", "请输入有效的输入目录")returnself.audio_files = []self.file_list.clear()# 显示扫描进度self.progress.setVisible(True)self.progress.setRange(0, 0) # 不确定进度模式QApplication.processEvents()# 获取选择的格式selected_format = self.format_combo.currentText()if selected_format == "所有支持格式":extensions = list(self.supported_formats.keys())else:extensions = [k for k, v in self.supported_formats.items() if v == selected_format]for root, _, files in os.walk(input_dir):for file in files:ext = os.path.splitext(file)[1][1:].lower()if ext in extensions:self.audio_files.append(os.path.join(root, file))self.file_list.addItems([os.path.basename(f) for f in self.audio_files])self.progress.setVisible(False)self.update_buttons()QMessageBox.information(self, "完成", f"找到 {len(self.audio_files)} 个音频文件")def process_selected(self):selected = self.file_list.selectedItems()if not selected:QMessageBox.warning(self, "警告", "请先选择要处理的文件")returnindices = [self.file_list.row(item) for item in selected]self.process_files(indices)def process_all(self):if not self.audio_files:QMessageBox.warning(self, "警告", "没有可处理的文件")returnreply = QMessageBox.question(self, "确认", f"确定要处理所有 {len(self.audio_files)} 个文件吗?",QMessageBox.Yes | QMessageBox.No)if reply == QMessageBox.Yes:self.process_files(range(len(self.audio_files)))def process_files(self, indices):method = self.method_combo.currentText().split()[0].lower()input_dir = self.input_path.text()output_dir = self.output_path.text() or os.path.join(input_dir, "cleaned_audio")total = len(indices)success = 0failed = 0self.progress.setVisible(True)self.progress.setMaximum(total)self.progress.setValue(0)os.makedirs(output_dir, exist_ok=True)for i, idx in enumerate(indices, 1):input_path = self.audio_files[idx]filename = os.path.basename(input_path)output_path = os.path.join(output_dir, filename)try:ext = os.path.splitext(input_path)[1][1:].lower()if method == "ffmpeg":result = self.process_with_ffmpeg(input_path, output_path)elif method == "mutagen":result = self.process_with_mutagen(input_path, output_path, ext)else: # 二进制处理result = self.process_binary(input_path, output_path, ext)if result:success += 1else:failed += 1except Exception as e:print(f"处理失败 {input_path}: {str(e)}")failed += 1self.progress.setValue(i)QApplication.processEvents()self.progress.setVisible(False)QMessageBox.information(self, "完成",f"处理完成!\n成功: {success}\n失败: {failed}\n输出目录: {output_dir}")def process_with_ffmpeg(self, input_path, output_path):"""使用FFmpeg处理"""try:cmd = ["ffmpeg","-i", input_path,"-map", "0:a","-c:a", "copy","-map_metadata", "-1",output_path,"-y" # 覆盖输出文件]subprocess.run(cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)return Trueexcept Exception as e:print(f"FFmpeg处理失败: {str(e)}")return Falsedef process_with_mutagen(self, input_path, output_path, ext):"""使用Mutagen处理不同格式的音频文件"""try:# 先复制文件if input_path != output_path:shutil.copy2(input_path, output_path)# 根据格式使用不同的处理方法if ext == "mp3":audio = MP3(output_path, ID3=ID3)if audio.tags:audio.tags.delall("APIC")audio.save()elif ext == "flac":audio = FLAC(output_path)if audio.pictures:audio.clear_pictures()audio.save()elif ext == "m4a":audio = MP4(output_path)if 'covr' in audio:del audio['covr']audio.save()elif ext == "ogg":try:audio = OggOpus(output_path)except:audio = OggVorbis(output_path)if 'metadata_block_picture' in audio:del audio['metadata_block_picture']audio.save()elif ext == "wma":audio = ASF(output_path)if hasattr(audio, 'tags') and 'WM/Picture' in audio.tags:del audio.tags['WM/Picture']audio.save()return Trueexcept Exception as e:print(f"Mutagen处理失败: {str(e)}")return Falsedef process_binary(self, input_path, output_path, ext):"""二进制方式处理(最后手段)"""try:if ext == "mp3":# MP3文件的简单二进制处理with open(input_path, "rb") as f:data = f.read()apic_pos = data.find(b"APIC")if apic_pos == -1:if input_path != output_path:shutil.copy2(input_path, output_path)return Truenew_data = data[:apic_pos] + data[apic_pos+4:]with open(output_path, "wb") as f:f.write(new_data)return Trueelse:# 其他格式直接复制(无法二进制处理)if input_path != output_path:shutil.copy2(input_path, output_path)return Falseexcept Exception as e:print(f"二进制处理失败: {str(e)}")return Falsedef update_buttons(self):has_files = bool(self.audio_files)self.process_btn.setEnabled(has_files)self.process_all_btn.setEnabled(has_files)def main():app = QApplication(sys.argv)# 设置应用程序样式app.setStyle('Fusion')window = AudioCoverRemover()window.show()sys.exit(app.exec_())if __name__ == "__main__":main()
🎯 性能优化建议
- 多线程处理:
# 可使用QThreadPool实现多线程处理from PyQt5.QtCore import QThreadPool, QRunnableclass Worker(QRunnable):def __init__(self, task_func):super().__init__()self.task_func = task_funcdef run(self):self.task_func()
-
缓存机制:
- 缓存已扫描文件列表
- 实现增量处理功能
-
元数据分析:
- 添加封面大小统计功能
- 支持预览被删除的封面
📝 总结
本文详细介绍了一款功能完善的音频封面删除工具的开发过程。通过结合PyQt5的GUI能力和Mutagen的音频处理能力,我们实现了一个用户友好且功能强大的应用程序。关键收获包括:
- 音频处理知识:深入理解了不同音频格式的元数据存储方式
- GUI开发技巧:掌握了现代化Qt界面设计方法
- 健壮性设计:学习了多种处理方法的兼容实现
该工具不仅具有实用价值,其开发过程也展示了Python在多媒体处理领域的强大能力。读者可以根据实际需求进一步扩展功能,如添加音频格式转换、元数据编辑等特性。
扩展思考:如何将此工具集成到自动化音乐管理流水线中?能否结合机器学习自动识别并分类音乐封面?
附录:完整代码
文中的完整Python代码已在前文展示,也可从GitHub仓库获取最新版本。建议在Python 3.7+环境中运行,并安装所有依赖库。
希望本文对您的音频处理项目有所启发!如有任何问题,欢迎在评论区讨论。
相关文章:
【Python开源】深度解析:一款高效音频封面批量删除工具的设计与实现
🎵 【Python开源】深度解析:一款高效音频封面批量删除工具的设计与实现 🌈 个人主页:创客白泽 - CSDN博客 🔥 系列专栏:🐍《Python开源项目实战》 💡 热爱不止于代码,热情…...
飞算 用到妙处 AI辅助编程 - 双击方法名,自动识别到上下文中很方便
1. 双击findtasktypedict方法。右侧箭头指向自动识别 2. 按照说的内容机型了修改...
msIT大模型推理迁移调优工具
msIT LLM大模型ATB推理精度工具 适用场景:大模型加速库推理精度分析工具能力:大模型推理精度工具msIT llm,提供基于加速库推理的精度调试工具,支持数据dump、精度比对、单算子预检、溢出检测、模型迁移等能力。 msIT LLM大模型…...
YOGA Air X ILL10(83CX)/YOGA 14 ILL10X(83LC)2025款恢复开箱状态原装出厂Win11系统OEM镜像
适用机型(MTM): 【83LC】链接:https://pan.baidu.com/s/1AwbFR9nccvyzS1pOCToMvA?pwdewjs 提取码:ewjs 【83CX】链接:https://pan.baidu.com/s/1wMRI8ETodVG59GBDVDLgQg?pwdn3nx 提取码:n3nx lenovo联想原装wi…...
使用Deployment部署运行Nginx和Apache服务
1.Deployment简介 : 在Kubernetes(k8s)中,Deployment 是一种核心控制器资源,用于管理无状态应用的声明式部署、扩展与更新。它通过定义应用的期望状态,由控制器自动维护实际状态与期望状态的一致性&#x…...
382_C++_在用户会话结束时,检查是否有其他会话仍然来自同一个客户端 IP 地址,没有连接状态设置为断开,否则为连接
之前出现的问题:重启管理机,工作机上面热备连接状态显示未连接 (此时是有一个工作机连接管理机的),所以正常应该是连接状态解决:根因分析: 重启管理机后,管理机给过来的cookie是空的,导致工作机同时存在两个管理机的session,在其中一个超时后,调用回调函数通知会话断开…...
【 Redis | 实战篇 短信登录 】
前言: 主要完成了基于Session实现登录,解决集群的Session共享问题,从而实现了基于Redis来实现共享Session登录 1.基于Session实现登录 1.1.发送短信验证码 步骤: 前端提交手机号 》校验手机号 》不符合返回错误信息࿰…...
AI(学习笔记第二课) 使用langchain进行AI开发
文章目录 AI(学习笔记第二课) 使用langchain进行AI开发学习内容:1. 使用背景2.创建python(pycharm community版)开发环境并连接deepseek2.1 创建python(pycharm community版)开发环境2.2 创建python工程2.3 写入初始py…...
如何查看某个文件中的特殊符号
Q:如何查看某个文件中的特殊符号,比如说是换行符之类的转义字符? 1,法1:使用cat -A cat -A filename可以看到-A本质上就是-vET,也就是 展示所有的字符,-v是显示非打印字符,这个需…...
venv环境里控制scapy版本和起trex v2.87
要在虚拟环境(venv)中控制Scapy版本并运行TRex v2.87,您可以按照以下步骤操作: 创建一个新的虚拟环境: python3 -m venv trex-env激活创建的虚拟环境。在Linux或macOS上: source trex-env/bin/activate在Wi…...
第五十四篇 AI与数据分析
一、AI数据分析就像做菜 想象你在厨房做一道新菜,AI数据分析的流程其实非常相似: 买菜(获取数据) 去市场挑选新鲜蔬菜 从Excel/数据库获取数据例:pd.read_csv(超市销售表.csv) 洗菜切菜(清洗数据&#x…...
C++面向对象编程入门:从类与对象说起(一)
C语言是面向过程,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题,而C面向的是对象,关注的是对象,将一件事拆解成多个对象,靠对象之间互交完成。 目录 类的定义 类的两种定义 …...
openwrt之UCI 增删改查(add/get/set /add_list...)
1,引入 UCI是openwrt的统一配置接口,所有的配置文件被存放在/etc/config/下,使用UCI工具操作具体可查询官网中的开发文章: [OpenWrt Wiki] The UCI systemhttps://openwrt.org/docs/guide-user/base-system/uciconifg <secti…...
TypeScript 中,属性修饰符
在 TypeScript 中,属性修饰符(Property Modifiers)是用于修饰类的属性或方法的关键字,它们可以改变属性或方法的行为和访问权限。TypeScript 提供了三种主要的属性修饰符:public、private 和 protected。此外ÿ…...
LeetCode 3341.到达最后一个房间的最少时间 I:Dijkstra算法(类似深搜)-简短清晰的话描述
【LetMeFly】3341.到达最后一个房间的最少时间 I:Dijkstra算法(类似深搜)-简短清晰的话描述 力扣题目链接:https://leetcode.cn/problems/find-minimum-time-to-reach-last-room-i/ 有一个地窖,地窖中有 n x m 个房间…...
http重新为https
1.先创建一个配置文件 主要方便实验 可以将主配置文件下的location全部注释掉,方便观察 2.配置新配置文件 server{ listen 80; listen 443 ssl; ssl_certificate /usr/local/nginx/conf.d/ssl/www.kgc.com.crt; ssl_certificate_key /usr/local/nginx/conf…...
2025最新免费视频号下载工具!支持Win/Mac,一键解析原画质+封面
软件介绍 适用于Windows 2025 最新5月蝴蝶视频号下载工具,免费使用,无广告且免费,支持对原视频和封面进行解析下载,亲测可用,现在很多工具都失效了,难得的几款下载视频号工具,大家且用且珍…...
CTF杂项入门(BUUCTF-Misc第一页)
写在前面 题目涵盖:BUUCTF 第一页杂项 涉及工具: 随波逐流、foremost、binwalk、honeyview、010editor、zipperello、archpr、wireshark、cyberchef、QR_Research、PNGCRC爆破、stegsolve、Audacity、河马、D盾、routerpassview、steghide,以…...
碰一碰发视频一键成片功能开发实践与技术解析
在数字化营销与内容传播领域,碰一碰发视频技术凭借便捷的交互体验,已成为实体商业引流的重要手段。而一键成片功能的融入,能够让用户在触碰 NFC 标签后,快速获取高质量的视频内容,进一步提升传播效率。本文将从功能需求…...
【CTFer成长之路】举足轻重的信息搜集
举足轻重的信息搜集 信息搜集 常见的搜集 题目描述: 一共3部分flag docker-compose.yml version: 3.2services:web:image: registry.cn-hangzhou.aliyuncs.com/n1book/web-information-backk:latestports:- 80:80启动方式 docker-compose up -d 题目Flag n1book{info_…...
centos搭建dokcer和vulhub
1、换源阿里云 2、安装docker与docker-compose 下载1.29.2 docker compose sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose 如果下载不了,可以…...
Linux系统下使用Kafka和Zookeeper
Apache Kafka 是一个分布式流处理平台,最初由 LinkedIn 开发,后来成为 Apache 软件基金会的顶级项目。它具有高吞吐量、可扩展性、持久性、容错性等特点,主要用于处理实时数据流。 Linux系统下使用Kafka 1.安装 Java Kafka 和 Zookeeper 都是基于 Java 开发的,所以需要先…...
vscode与keil的乱码不兼容问题
都用英文注释 中文注释的话,打开vscode的自动识别格式,如下 解决VSCode中文乱码 自动识别也可以设置识别优先级,把GB2312和UTF8排在自动识别序列前面(因为keil默认就是GB2312) 4.!!!在暂存更改的时候,不要把vscode的设置给暂存了ÿ…...
C++类和对象:构造函数、析构函数、拷贝构造函数
引言 介绍:C类和对象:构造函数、析构函数、拷贝构造函数 _涂色_博主主页 C基础专栏 一、类的默认成员函数 先认识一下类中的默认成员函数: 默认成员函数就是用户没有显式实现,编译器会自动生成的成员函数称为默认成员函数。⼀个类…...
【FAQ】HarmonyOS SDK 闭源开放能力 — PDF Kit
1.问题描述: 预览PDF文件,文档上所描述的loadDocument接口,可以返回文件的状态,并无法实现PDF的预览,是否有能预览PDF相关接口? 解决方案: 1、执行loadDocument进行加载PDF文件后,…...
Spring Boot 3 + Undertow 服务器优化配置
优化背景 当你的application需要支持瞬时高并发的时候,tomcat已经不在是最优的选择,我们可以改为Undertow,并对其进行优化。 Undertow 是一个轻量级的、高性能的Java Web 服务器,由JBoss 开发并开源。它是基于非阻塞(…...
网易游戏 Flink 云原生实践
摘要:本文整理自网易游戏实时计算&数据湖平台负责人林小铂老师和网易游戏大数据开发工程师陈宇智老师,在Flink Forward Asia 2024 云原生专场的分享。主要分为四个部分: 1、背景 2、架构演进 3、实践挑战 4、总结和展望 01.背景 Flink 在…...
使用迁移学习的自动驾驶汽车信息物理系统安全策略
信息物理系统 (CPS) 是一种新兴系统,它通过信息通信基础设施,实现控制系统、传感器、执行器和周围环境等物理组件之间有效的实时通信与协作 (C&C)。自动驾驶汽车 (AV) 是大量采用 CPS 方法的领域之一,旨在通过降低能源消耗和空气污染来改善智慧城市中的人们生活。因此,…...
《算法导论(第4版)》阅读笔记:p11-p13
《算法导论(第4版)》学习第 8 天,p11-p13 总结,总计 3 页。 一、技术总结 无。 二、英语总结(生词:2) 1.precious (1)precious: pretium(“value, worth, price”) adj. of great value(宝贵,珍贵)。 (2)示例 Computing t…...
Qt 编译 sqldrivers之psql
编译postgres pgsql驱动 下载驱动源码修改配置文件编译 下载驱动源码 // 源代码下载 https://download.qt.io/archive/qt/5.15/5.15.2/submodules/驱动目录:qtbase-everywhere-src-5.15.2\src\plugins\sqldrivers 修改配置文件 打开pro文件 右键点击添加库 此处的为debu…...
查看单元测试覆盖率
文章目录 1、POM文件配置2、编写单元测试3、执行单元测试4、查看单元测试覆盖率 1、POM文件配置 pom文件配置jacoco插件 <!-- 生成JaCoCo覆盖率数据插件 --> <plugin><groupId>org.jacoco</groupId><artifactId>jacoco-maven-plugin</artif…...
ASP.NET Core 中实现 Markdown 渲染中间件
文章目录 前言一、核心功能二、实现步骤1)安装依赖包2)创建中间件类3)中间件扩展方法4)在Program.cs配置5)模板文件示例6)*.md文件示例7)缓存优化8)使用示例 三、注意事项总结 前言 …...
AI学习路径
一、AI入门与系统课程 (1)《开启AI革命:7天从小白到大神》 简介:保姆级教学,覆盖AI基础知识、机器学习、深度学习、自然语言处理(NLP)、大语言模型(LLM)等,…...
基于Kubernetes的Apache Pulsar云原生架构解析与集群部署指南(下)
文章目录 k8s安装部署Pulsar集群前期准备版本要求 安装 Pulsar Helm chart管理pulsarClustersBrokersTopic k8s安装部署Pulsar集群 前期准备 版本要求 Kubernetes 集群,版本 1.14 或更高版本Helm v3(3.0.2 或更高版本)数据持久化ÿ…...
B站搜索关键词全攻略:掌握B站搜索关键词的运作机制
在拥有超过7亿月活用户的B站,每天都有海量视频涌入平台。无论是普通用户还是内容创作者,掌握B站搜索关键词的运作机制,都能极大提升平台体验和内容价值。本文将从用户和创作者双重视角,深入解析B站搜索关键词的应用技巧和优化策略…...
Windows系统安装Cursor与远程调用本地模型QWQ32B实现AI辅助开发
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...
DBeaver查询PostgreSQL的只读模式
问题 DBeaver查询PostgreSQL数据表时,注意到经常会出现“Detect unique identifiers" 这个阶段,几乎需要花费10s时间,想着挺浪费时间的。 问题解决办法 把”读取数据表元数据(唯一键)"这个复选框选项去掉,再进行查询…...
C++内存管理与模板初阶详解:从原理到实践
目录: 一、C/C内存管理1. 内存区域划分2. 动态内存管理3. 底层原理:operator new/delete4.new和delete的实现原理5. 定位new(了解即可) 二、模板初阶1. 泛型编程2. 函数模板实例化隐式实例化:编译器自动推导类型显式实…...
02-GBase 8s 事务型数据库 客户端工具dbaccess
dbaccess概述 数据库产品通常会提供一个命令行客户端工具。 数据库厂商 命令行客户端 Oracle sqlplus MySQL mysql Marladb mysql GBase 8s dbaccess Kingbase ES ksql DM8 disql dbaccess 是 GBase 8s 数…...
【kubernetes】通过Sealos 命令行工具一键部署k8s集群
一、前言 1、sealos安装k8s集群官网:K8s > Quick-start > Deploy-kubernetes | Sealos Docs 2、本文安装的k8s版本为v1.28.9 3、以下是一些基本的安装要求: 每个集群节点应该有不同的主机名。主机名不要带下划线。所有节点的时间需要同步。需要…...
【Pandas】pandas DataFrame abs
Pandas2.2 DataFrame Computations descriptive stats 方法描述DataFrame.abs()用于返回 DataFrame 中每个元素的绝对值 pandas.DataFrame.abs() pandas.DataFrame.abs() 方法用于返回 DataFrame 中每个元素的绝对值。该方法适用于包含数值型数据的 DataFrame,对…...
如何在 C# 和 .NET 中打印 DataGrid
DataGrid 是 .NET 架构中一个功能极其丰富的组件,或许也是最复杂的组件之一。写这篇文章是为了回答“我到底该如何打印 DataGrid 及其内容”这个问题。最初即兴的建议是使用我的屏幕截图文章来截取表单,但这当然无法解决打印 DataGrid 中虚拟显示的无数行…...
使用DEEPSEEK快速修改QT创建的GUI
QT的GUI,本质上是使用XML进行描述的,在QT CREATOR的界面编辑处,按CTRL2 切换到代码视图,CTRL3切换到编辑器视图。 CTRL2 切换到代码视图 CTRL3 切换到编辑器视图 鼠标左键点击代码视图中,按CTRLA → CTRLC复制XML代码…...
前端面试宝典---JavaScript import 与 Node.js require 的区别
import 和 require 来自不同的规范: import 是 ES6(ECMAScript 2015)模块系统的一部分,是 JavaScript 语言的标准语法 require 是 CommonJS 规范的一部分,最初为 Node.js 环境设计 加载方式: require() …...
C++入门小馆 :多态
嘿,各位技术潮人!好久不见甚是想念。生活就像一场奇妙冒险,而编程就是那把超酷的万能钥匙。此刻,阳光洒在键盘上,灵感在指尖跳跃,让我们抛开一切束缚,给平淡日子加点料,注入满满的pa…...
极简远程革命:打破公网桎梏,重塑数字生活新体验
简远程革命:节点小宝,让家庭与职场无缝互联 ——打破公网桎梏,重塑数字生活新体验 引言:当公网IP成为过去式 在2025年的今天,80%的家庭仍因缺乏公网IP而深陷远程访问困境。NAS玩家为端口映射焦头烂额,家长…...
Linux 网络管理 的实战代码示例
涵盖网络接口配置、连接测试、防火墙管理、数据包捕获、服务监控等核心场景。每个示例均附带详细注释和操作说明,帮助您深入理解 Linux 网络管理的实战技巧。 1. 网络接口配置与管理 1.1 使用 ip 命令管理网络接口 ip 是现代 Linux 系统中管理网络的主要工具,功能比 ifcon…...
OPCUA,OPCDA与MODBUS学习笔记
MODBUS与OPC之间的关系是什么? 前言 OPC协议(OLE for Process Control,即过程控制的OLE)是一种标准化的通信协议,旨在帮助不同厂商的设备、控制系统和软件之间进行数据交换。OPC协议的目标是提供一种统一的接口&…...
千星计划小程序开发方案
千星计划小程序开发方案 (基于2025年行业实践与系统需求) 一、核心功能架构 1.用户管理模块 用户分层管理:普通用户、达人、合伙人三级身份体系,支持身份升级审核与权限配置 实名认证与资质审核:对接公安系统…...
【RAG技术全景解读】从原理到工业级应用实践
目录 🌟 前言🏗️ 技术背景与价值🚨 当前技术痛点🛠️ 解决方案概述👥 目标读者说明 🔍 一、技术原理剖析📐 核心概念图解💡 核心作用讲解⚙️ 关键技术模块说明⚖️ 技术选型对比 &…...