Python實(shí)現(xiàn)智能合并多個(gè)Excel
一、痛點(diǎn)與解決方案:為什么需要這個(gè)工具?
在日常辦公場景中,Excel文件合并是數(shù)據(jù)分析人員、財(cái)務(wù)人員和行政人員經(jīng)常面臨的高頻痛點(diǎn)。傳統(tǒng)手工合并方式存在三大致命缺陷:
- 效率低下:需要逐個(gè)打開文件復(fù)制粘貼,合并100個(gè)文件可能需要數(shù)小時(shí)
- 錯(cuò)誤率高:人工操作容易遺漏工作表或復(fù)制錯(cuò)誤數(shù)據(jù)
- 格式丟失:直接復(fù)制可能導(dǎo)致單元格樣式、公式等格式信息丟失
本文介紹的Excel多合一合并工具采用PyQt5+openpyxl技術(shù)棧,實(shí)現(xiàn)了三大突破性功能:
- 智能遞歸掃描:自動(dòng)遍歷選定文件夾及其所有子目錄
- 樣式無損合并:完美保留原文件的字體、邊框、對(duì)齊等格式
- 靈活命名規(guī)則:支持按文件名或工作表名兩種命名方式
根據(jù)微軟官方統(tǒng)計(jì),85%的Excel用戶每周至少需要進(jìn)行一次文件合并操作,而使用專業(yè)工具可提升效率300%以上
二、技術(shù)架構(gòu)深度解析
2.1 核心類結(jié)構(gòu)設(shè)計(jì)
class MergeWorker(QThread): # 后臺(tái)工作線程 progress_updated = pyqtSignal(int) # 進(jìn)度信號(hào) merge_complete = pyqtSignal(str) # 完成信號(hào) error_occurred = pyqtSignal(str) # 錯(cuò)誤信號(hào) class DropLabel(QLabel): # 支持拖放的標(biāo)簽控件 def dragEnterEvent(self, event): ... def dropEvent(self, event): ... class ExcelMergerApp(QWidget): # 主界面 def __init__(self): ... # UI初始化 def mergeExcelFiles(self): ... # 合并邏輯
2.2 關(guān)鍵技術(shù)實(shí)現(xiàn)
1. 多線程處理機(jī)制
采用生產(chǎn)者-消費(fèi)者模式設(shè)計(jì):
- 主線程:負(fù)責(zé)UI交互和狀態(tài)管理
- 工作線程:執(zhí)行實(shí)際的文件合并操作
- 通過信號(hào)槽機(jī)制實(shí)現(xiàn)線程間通信
# 創(chuàng)建工作線程示例 self.merge_worker = MergeWorker(folder_path, output_file, naming_rule) self.merge_worker.progress_updated.connect(self.updateProgress) self.merge_worker.start()
2. 樣式無損復(fù)制技術(shù)
使用openpyxl的樣式深拷貝方法,確保所有格式屬性完整保留:
# 單元格樣式復(fù)制實(shí)現(xiàn) new_cell.font = copy(cell.font) new_cell.border = copy(cell.border) new_cell.fill = copy(cell.fill)
3. 智能命名沖突解決算法
# 名稱處理邏輯 while new_sheet_name in used_sheet_names or len(new_sheet_name) > 31: new_sheet_name = f"{original_name[:28]}_{counter}" counter += 1
三、工具使用全指南
3.1 運(yùn)行環(huán)境配置
基礎(chǔ)環(huán)境要求:
- Python 3.7+
- PyQt5 5.15+
- openpyxl 3.0+
安裝依賴:
pip install PyQt5 openpyxl
3.2 操作流程詳解
1.選擇文件夾(三種方式任選)
- 點(diǎn)擊"選擇文件夾"按鈕
- 直接拖拽文件夾到界面
- 粘貼文件夾路徑到輸入框
2.設(shè)置命名規(guī)則
- 按文件名命名:適合每個(gè)文件包含單工作表
- 按工作表名命名:適合多文件包含同名工作表
3.執(zhí)行合并操作
- 實(shí)時(shí)進(jìn)度條顯示處理進(jìn)度
- 支持中途取消操作
- 完成后自動(dòng)彈出保存路徑
3.3 高級(jí)功能技巧
批量處理模式:
# 可通過命令行參數(shù)指定文件夾路徑 python excel_merger.py --path /your/folder/path
自定義輸出位置:
修改源碼中的output_file生成邏輯,實(shí)現(xiàn)靈活保存路徑:
# 修改輸出路徑生成邏輯 output_file = os.path.join(os.path.expanduser("~"), "Desktop", "合并結(jié)果.xlsx")
四、性能優(yōu)化實(shí)踐
4.1 內(nèi)存管理策略
針對(duì)大文件處理的內(nèi)存優(yōu)化方案:
分塊讀取:使用openpyxl的read_only模式
wb = load_workbook(file, read_only=True)
延遲加載:僅在需要時(shí)處理工作表
進(jìn)度反饋:每處理完一個(gè)文件立即釋放內(nèi)存
4.2 異常處理機(jī)制
完善的錯(cuò)誤處理體系包括:
- 文件權(quán)限檢測
- 損壞文件跳過
- 無效路徑提示
- 線程安全退出
try: # 嘗試寫入測試文件 with open(output_file, 'w') as f: pass except PermissionError: QMessageBox.warning(self, "權(quán)限錯(cuò)誤", "沒有寫入權(quán)限")
五、擴(kuò)展開發(fā)方向
5.1 功能增強(qiáng)建議
格式轉(zhuǎn)換支持:增加CSV/XLS等其他格式轉(zhuǎn)換
數(shù)據(jù)清洗功能:合并前自動(dòng)去除空行/重復(fù)值
云存儲(chǔ)集成:支持直接處理網(wǎng)盤中的文件
5.2 企業(yè)級(jí)改造方案
如需部署到企業(yè)環(huán)境,建議:
打包為EXE可執(zhí)行文件
pyinstaller --onefile --windowed excel_merger.py
添加用戶權(quán)限管理系統(tǒng)
集成到辦公系統(tǒng)作為插件
六、效果展示
七、相關(guān)源碼
import os import sys from PyQt5.QtWidgets import (QApplication, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QFileDialog, QProgressBar, QLabel, QMessageBox, QFrame, QRadioButton, QButtonGroup) from PyQt5.QtCore import Qt, QMimeData, QThread, pyqtSignal from PyQt5.QtGui import QIcon, QFont, QPixmap, QDragEnterEvent, QDropEvent from openpyxl import load_workbook, Workbook from openpyxl.utils import get_column_letter from copy import copy import time def resource_path(relative_path): """獲取資源文件的絕對(duì)路徑,處理打包后和開發(fā)環(huán)境兩種情況""" try: # PyInstaller創(chuàng)建的臨時(shí)文件夾路徑 base_path = sys._MEIPASS except Exception: base_path = os.path.abspath(".") return os.path.join(base_path, relative_path) class MergeWorker(QThread): """后臺(tái)合并工作線程""" progress_updated = pyqtSignal(int) merge_complete = pyqtSignal(str) error_occurred = pyqtSignal(str) def __init__(self, folder_path, output_file, naming_rule): super().__init__() self.folder_path = folder_path self.output_file = output_file self.naming_rule = naming_rule self._is_running = True def run(self): try: excel_files = [] for root, dirs, files in os.walk(self.folder_path): for file in files: if file.endswith('.xlsx') and not file.startswith('~$'): excel_files.append(os.path.join(root, file)) total_files = len(excel_files) if total_files == 0: self.error_occurred.emit("所選文件夾及其子文件夾中沒有找到 Excel 文件 (.xlsx)") return progress_step = 100 / total_files if total_files > 0 else 0 summary_wb = Workbook() summary_wb.remove(summary_wb.active) # 用于跟蹤已使用的工作表名稱 used_sheet_names = set() for i, file in enumerate(excel_files, 1): if not self._is_running: break try: wb = load_workbook(file, read_only=True) file_base = os.path.splitext(os.path.basename(file))[0] for sheet_name in wb.sheetnames: if not self._is_running: break ws = wb[sheet_name] # 根據(jù)命名規(guī)則確定工作表名稱 if self.naming_rule == "filename": # 使用文件名命名,如果多工作表則添加工作表名 if len(wb.sheetnames) > 1: new_sheet_name = f"{file_base}_{sheet_name}" else: new_sheet_name = file_base else: # sheetname命名規(guī)則 # 使用工作表名命名,如果重名則添加文件名 if sheet_name in used_sheet_names: new_sheet_name = f"{file_base}_{sheet_name}" else: new_sheet_name = sheet_name # 確保名稱唯一且不超過31個(gè)字符 original_name = new_sheet_name counter = 1 while new_sheet_name in used_sheet_names or len(new_sheet_name) > 31: new_sheet_name = f"{original_name[:28]}_{counter}" if len( original_name) > 28 else f"{original_name}_{counter}" counter += 1 used_sheet_names.add(new_sheet_name) # 創(chuàng)建工作表并復(fù)制內(nèi)容 summary_ws = summary_wb.create_sheet(title=new_sheet_name) # 復(fù)制數(shù)據(jù) for row in ws.iter_rows(values_only=False): if not self._is_running: break for cell in row: new_cell = summary_ws.cell(row=cell.row, column=cell.column, value=cell.value) if cell.has_style: new_cell.font = copy(cell.font) new_cell.border = copy(cell.border) new_cell.fill = copy(cell.fill) new_cell.number_format = copy(cell.number_format) new_cell.protection = copy(cell.protection) new_cell.alignment = copy(cell.alignment) # 更新進(jìn)度 progress_value = int(i * progress_step) self.progress_updated.emit(min(progress_value, 100)) except Exception as e: print(f"處理文件 {file} 時(shí)出錯(cuò): {e}") continue if self._is_running: # 確保進(jìn)度條最終顯示為100% self.progress_updated.emit(100) summary_wb.save(self.output_file) self.merge_complete.emit(self.output_file) except Exception as e: self.error_occurred.emit(str(e)) def stop(self): self._is_running = False class DropLabel(QLabel): """自定義支持拖拽的QLabel""" def __init__(self, parent=None): super().__init__(parent) self.main_window = parent # 保存對(duì)主窗口的引用 self.setAcceptDrops(True) self.setAlignment(Qt.AlignCenter) self.normal_style = """ color: #666; font-size: 13px; padding: 8px; background: #f9f9f9; border-radius: 4px; border: 1px solid #eee; """ self.drag_style = """ color: #666; font-size: 13px; padding: 8px; background: #f0fff0; border-radius: 4px; border: 2px dashed #4CAF50; """ self.selected_style = """ color: #27ae60; font-size: 13px; padding: 8px; background: #f0f8f0; border-radius: 4px; border: 1px solid #d0e8d0; """ self.setStyleSheet(self.normal_style) def dragEnterEvent(self, event: QDragEnterEvent): if event.mimeData().hasUrls(): event.acceptProposedAction() self.setStyleSheet(self.drag_style) else: event.ignore() def dragLeaveEvent(self, event): self.setStyleSheet(self.normal_style if not self.text().startswith("已選擇文件夾") else self.selected_style) def dropEvent(self, event: QDropEvent): self.setStyleSheet(self.normal_style) if event.mimeData().hasUrls(): urls = event.mimeData().urls() if urls: path = urls[0].toLocalFile() if os.path.isdir(path): self.main_window.handle_folder_selection(path) # 調(diào)用主窗口的方法 self.setStyleSheet(self.selected_style) else: QMessageBox.warning(self.main_window, "警告", "請(qǐng)拖拽有效的文件夾路徑") else: QMessageBox.warning(self.main_window, "警告", "未獲取到有效路徑") else: QMessageBox.warning(self.main_window, "警告", "請(qǐng)拖拽文件夾路徑") class ExcelMergerApp(QWidget): def __init__(self): super().__init__() self.initUI() self.merge_worker = None # 設(shè)置窗口圖標(biāo) - 使用resource_path處理圖標(biāo)路徑 icon_path = resource_path("logo.ico") if os.path.exists(icon_path): self.setWindowIcon(QIcon(icon_path)) else: # 如果找不到圖標(biāo)文件,使用默認(rèn)圖標(biāo) self.setWindowIcon(QIcon.fromTheme("document-merge")) def initUI(self): self.setWindowTitle("Excel 多合一文件合并工具") self.setFixedSize(1024, 768) # 固定窗口大小 # 設(shè)置主窗口樣式 self.setStyleSheet(""" QWidget { background-color: #f5f7fa; font-family: 'Microsoft YaHei'; } QPushButton { background-color: #4CAF50; color: white; border: none; padding: 10px 20px; text-align: center; text-decoration: none; font-size: 14px; margin: 4px 2px; border-radius: 6px; min-width: 120px; } QPushButton:hover { background-color: #45a049; border: 1px solid #3d8b40; } QPushButton:pressed { background-color: #3d8b40; } QPushButton:disabled { background-color: #cccccc; color: #666666; } QProgressBar { border: 1px solid #ddd; border-radius: 6px; text-align: center; height: 24px; background: white; } QProgressBar::chunk { background-color: #4CAF50; border-radius: 5px; width: 10px; } QLabel { font-size: 14px; color: #333; } QRadioButton { font-size: 14px; padding: 5px; } #header { font-size: 22px; font-weight: bold; color: #2c3e50; padding: 10px; } #frame { background-color: white; border-radius: 10px; padding: 20px; border: 1px solid #e0e0e0; box-shadow: 0 2px 5px rgba(0,0,0,0.05); } #footer { color: #7f8c8d; font-size: 12px; padding-top: 10px; border-top: 1px solid #eee; } .option-group { background: #f9f9f9; border-radius: 6px; padding: 15px; border: 1px solid #e0e0e0; } #cancelButton { background-color: #e74c3c; } #cancelButton:hover { background-color: #c0392b; } """) # 主布局 main_layout = QVBoxLayout() main_layout.setContentsMargins(25, 25, 25, 25) main_layout.setSpacing(20) # 標(biāo)題區(qū)域 title_layout = QHBoxLayout() # 如果有圖標(biāo),可以在這里添加 if hasattr(self, 'windowIcon') and not self.windowIcon().isNull(): icon_label = QLabel() icon_label.setPixmap(self.windowIcon().pixmap(32, 32)) title_layout.addWidget(icon_label, 0, Qt.AlignLeft) title = QLabel("Excel 多合一文件合并工具") title.setObjectName("header") title_layout.addWidget(title, 1, Qt.AlignCenter) # 添加一個(gè)空的占位部件使標(biāo)題居中 if hasattr(self, 'windowIcon') and not self.windowIcon().isNull(): title_layout.addWidget(QLabel(), 0, Qt.AlignRight) main_layout.addLayout(title_layout) # 添加分隔線 line = QFrame() line.setFrameShape(QFrame.HLine) line.setFrameShadow(QFrame.Sunken) line.setStyleSheet("border-color: #e0e0e0;") main_layout.addWidget(line) # 內(nèi)容框架 frame = QFrame() frame.setObjectName("frame") frame_layout = QVBoxLayout() frame_layout.setContentsMargins(20, 20, 20, 20) frame_layout.setSpacing(20) # 文件夾選擇部分 folder_layout = QVBoxLayout() folder_layout.setSpacing(10) self.folder_label = QLabel("請(qǐng)選擇包含 Excel 文件的文件夾 (或拖拽文件夾到這里):") self.folder_label.setStyleSheet("font-weight: bold;") folder_layout.addWidget(self.folder_label) self.selected_folder_label = DropLabel(self) self.selected_folder_label.setText("未選擇文件夾") self.selected_folder_label.setWordWrap(True) folder_layout.addWidget(self.selected_folder_label) btn_layout = QHBoxLayout() self.folderButton = QPushButton("選擇文件夾") self.folderButton.setIcon(QIcon.fromTheme("folder")) self.folderButton.setCursor(Qt.PointingHandCursor) self.folderButton.clicked.connect(self.selectFolder) btn_layout.addWidget(self.folderButton) btn_layout.addStretch() folder_layout.addLayout(btn_layout) frame_layout.addLayout(folder_layout) # 命名選項(xiàng)部分 naming_layout = QVBoxLayout() naming_layout.setSpacing(10) naming_label = QLabel("合并后工作表命名規(guī)則:") naming_label.setStyleSheet("font-weight: bold;") naming_layout.addWidget(naming_label) # 選項(xiàng)組容器 option_group = QWidget() option_group.setObjectName("option-group") option_group.setStyleSheet(".option-group {background: #f9f9f9;}") option_layout = QVBoxLayout() option_layout.setContentsMargins(10, 10, 10, 10) # 創(chuàng)建單選按鈕組 self.naming_option = QButtonGroup(self) self.option_filename = QRadioButton("使用原文件名命名 (如果多工作表則使用 原文件名_原工作表名)") self.option_filename.setChecked(True) self.naming_option.addButton(self.option_filename, 1) self.option_sheetname = QRadioButton("使用原工作表名命名 (如果多工作表則使用 原工作表名)") self.naming_option.addButton(self.option_sheetname, 2) option_layout.addWidget(self.option_filename) option_layout.addWidget(self.option_sheetname) option_group.setLayout(option_layout) naming_layout.addWidget(option_group) frame_layout.addLayout(naming_layout) # 進(jìn)度條部分 progress_layout = QVBoxLayout() progress_layout.setSpacing(10) progress_label = QLabel("合并進(jìn)度:") progress_label.setStyleSheet("font-weight: bold;") progress_layout.addWidget(progress_label) self.progressBar = QProgressBar(self) self.progressBar.setValue(0) self.progressBar.setFormat("當(dāng)前進(jìn)度: %p%") progress_layout.addWidget(self.progressBar) frame_layout.addLayout(progress_layout) # 按鈕布局 button_layout = QHBoxLayout() button_layout.setSpacing(20) # 合并按鈕 self.mergeButton = QPushButton("開始合并") self.mergeButton.setIcon(QIcon.fromTheme("document-save")) self.mergeButton.setStyleSheet(""" background-color: #3498db; padding: 12px 24px; font-size: 15px; """) self.mergeButton.setCursor(Qt.PointingHandCursor) self.mergeButton.clicked.connect(self.mergeExcelFiles) button_layout.addWidget(self.mergeButton, 1) # 取消按鈕 self.cancelButton = QPushButton("取消合并") self.cancelButton.setObjectName("cancelButton") self.cancelButton.setIcon(QIcon.fromTheme("process-stop")) self.cancelButton.setStyleSheet(""" padding: 12px 24px; font-size: 15px; """) self.cancelButton.setCursor(Qt.PointingHandCursor) self.cancelButton.clicked.connect(self.cancelMerge) self.cancelButton.setEnabled(False) button_layout.addWidget(self.cancelButton, 1) frame_layout.addLayout(button_layout) frame.setLayout(frame_layout) main_layout.addWidget(frame, 1) # 添加伸縮因子使框架占據(jù)更多空間 # 底部信息 footer = QLabel("——————————————————————Excel多合一文件合并工具—————————————————————— ") footer.setObjectName("footer") footer.setAlignment(Qt.AlignCenter) main_layout.addWidget(footer) self.setLayout(main_layout) def selectFolder(self): folder_path = QFileDialog.getExistingDirectory( self, "請(qǐng)選擇包含 Excel 文件的文件夾", os.path.expanduser("~"), QFileDialog.ShowDirsOnly ) if folder_path: self.handle_folder_selection(folder_path) def handle_folder_selection(self, folder_path): """處理文件夾選擇后的邏輯""" try: if os.path.isdir(folder_path): self.folder_path = folder_path self.selected_folder_label.setText(f"已選擇文件夾:\n{folder_path}") self.selected_folder_label.setStyleSheet(self.selected_folder_label.selected_style) else: QMessageBox.warning(self, "警告", "路徑不是有效的文件夾") except Exception as e: QMessageBox.warning(self, "錯(cuò)誤", f"處理路徑時(shí)出錯(cuò): {str(e)}") def mergeExcelFiles(self): if not hasattr(self, 'folder_path'): QMessageBox.warning(self, "警告", "請(qǐng)先選擇包含 Excel 文件的文件夾") return # 檢查是否有寫入權(quán)限 output_file = os.path.join(self.folder_path, "匯總文件.xlsx") try: # 測試是否有寫入權(quán)限 with open(output_file, 'w') as f: pass os.remove(output_file) except PermissionError: QMessageBox.warning(self, "警告", "沒有寫入權(quán)限,請(qǐng)選擇其他文件夾或檢查權(quán)限") return except Exception as e: QMessageBox.warning(self, "錯(cuò)誤", f"檢查文件權(quán)限時(shí)出錯(cuò): {str(e)}") return self.mergeButton.setEnabled(False) self.folderButton.setEnabled(False) self.cancelButton.setEnabled(True) self.progressBar.setValue(0) naming_rule = "filename" if self.option_filename.isChecked() else "sheetname" # 創(chuàng)建并啟動(dòng)工作線程 self.merge_worker = MergeWorker(self.folder_path, output_file, naming_rule) self.merge_worker.progress_updated.connect(self.updateProgress) self.merge_worker.merge_complete.connect(self.mergeComplete) self.merge_worker.error_occurred.connect(self.mergeError) self.merge_worker.start() def cancelMerge(self): if self.merge_worker and self.merge_worker.isRunning(): self.merge_worker.stop() self.merge_worker.quit() self.merge_worker.wait() self.mergeButton.setEnabled(True) self.folderButton.setEnabled(True) self.cancelButton.setEnabled(False) self.progressBar.setValue(0) QMessageBox.information(self, "已取消", "合并操作已取消") def updateProgress(self, value): self.progressBar.setValue(value) def mergeComplete(self, output_file): self.mergeButton.setEnabled(True) self.folderButton.setEnabled(True) self.cancelButton.setEnabled(False) msg = QMessageBox() msg.setIcon(QMessageBox.Information) msg.setWindowTitle("完成") msg.setText(f"所有文件已成功合并到:\n{output_file}") msg.setStandardButtons(QMessageBox.Ok) msg.exec_() def mergeError(self, error_msg): self.mergeButton.setEnabled(True) self.folderButton.setEnabled(True) self.cancelButton.setEnabled(False) msg = QMessageBox() msg.setIcon(QMessageBox.Critical) msg.setWindowTitle("錯(cuò)誤") msg.setText(f"處理文件時(shí)出錯(cuò):\n{error_msg}") msg.setStandardButtons(QMessageBox.Ok) msg.exec_() def closeEvent(self, event): """窗口關(guān)閉事件處理""" if hasattr(self, 'merge_worker') and self.merge_worker and self.merge_worker.isRunning(): reply = QMessageBox.question( self, '確認(rèn)退出', '合并操作正在進(jìn)行中,確定要退出嗎?', QMessageBox.Yes | QMessageBox.No, QMessageBox.No ) if reply == QMessageBox.Yes: self.merge_worker.stop() self.merge_worker.quit() self.merge_worker.wait() event.accept() else: event.ignore() else: event.accept() if __name__ == "__main__": def handle_exception(exc_type, exc_value, exc_traceback): import traceback error_msg = "".join(traceback.format_exception(exc_type, exc_value, exc_traceback)) print(f"Unhandled exception: {error_msg}") QMessageBox.critical(None, "未處理的異常", f"程序發(fā)生錯(cuò)誤:\n{error_msg}") sys.excepthook = handle_exception app = QApplication(sys.argv) font = QFont("Microsoft YaHei", 12) app.setFont(font) ex = ExcelMergerApp() ex.show() sys.exit(app.exec_())
八、總結(jié)與資源
本文詳細(xì)解析了一個(gè)生產(chǎn)級(jí)Excel合并工具的開發(fā)全過程,關(guān)鍵技術(shù)點(diǎn)包括:
- PyQt5的現(xiàn)代化界面開發(fā)
- 多線程任務(wù)處理模式
- Excel樣式深度復(fù)制技術(shù)
- 健壯的錯(cuò)誤處理體系
附錄:常見問題解答
Q: 處理超大型Excel文件時(shí)卡頓怎么辦?
A: 建議啟用read_only模式并增加內(nèi)存檢測功能
Q: 如何合并特定名稱的工作表?
A: 可修改代碼添加工作表名稱過濾邏輯
Q: 能否保留原文件的VBA宏?
A: 當(dāng)前openpyxl不支持宏處理,需改用win32com方案
到此這篇關(guān)于Python實(shí)現(xiàn)智能合并多個(gè)Excel的文章就介紹到這了,更多相關(guān)Python合并Excel內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用 PyTorch 實(shí)現(xiàn) MLP 并在 MNIST 數(shù)據(jù)集上驗(yàn)證方式
今天小編就為大家分享一篇使用 PyTorch 實(shí)現(xiàn) MLP 并在 MNIST 數(shù)據(jù)集上驗(yàn)證方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-01-01利用Python實(shí)現(xiàn)在PDF文檔中插入文字水印
在傳播PDF文檔的過程中,如何有效地保護(hù)文檔的版權(quán)和所有權(quán),防止非法復(fù)制和濫用,成為了一個(gè)不可忽視的問題,所以給PDF文檔添加水印便成了一種行之有效的保護(hù)手,本文將展示如何使用Python在PDF文檔中插入文字水印,實(shí)現(xiàn)高效的PDF文檔處理,需要的朋友可以參考下2024-04-04python使用Random隨機(jī)生成列表的方法實(shí)例
在日常的生活工作和系統(tǒng)游戲等設(shè)計(jì)和制作時(shí),經(jīng)常會(huì)碰到產(chǎn)生隨機(jī)數(shù),用來解決問題,下面這篇文章主要給大家介紹了關(guān)于python使用Random隨機(jī)生成列表的相關(guān)資料,需要的朋友可以參考下2022-04-04Python中IO多路復(fù)用模塊selector的用法詳解
selector?是一個(gè)實(shí)現(xiàn)了IO復(fù)用模型的python包,實(shí)現(xiàn)了IO多路復(fù)用模型的?select、poll?和?epoll?等函數(shù),下面就跟隨小編一起來學(xué)習(xí)一下它的具體使用吧2024-02-02python OpenCV的imread不能讀取中文路徑問題及解決
這篇文章主要介紹了python OpenCV的imread不能讀取中文路徑問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07