diff --git a/src/docx.py b/src/docx.py new file mode 100644 index 0000000..858de2a --- /dev/null +++ b/src/docx.py @@ -0,0 +1,15 @@ + +def a(): + try: + m + except Exception as e: + raise Exception("拷贝 pptx 文件错误") from e + + +def b(): + try: + a() + except Exception as e: + print('捕获到异常:{}'.format(e)) + +b() \ No newline at end of file diff --git a/src/excel.py b/src/excel.py new file mode 100644 index 0000000..f10d136 --- /dev/null +++ b/src/excel.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- +''' +@文件 :excel.py +@时间 :2023/07/20 14:02:21 +@作者 :aliha +@版本 :1.0 +@依赖 :无 +@说明 :移除限制xlsx的限制密码 +''' + + +from lxml import etree +import shutil +import os +from util import delDirs, filterFiles, unZip, zipDir, mkdir + +keyNode = ['sheetProtection', 'workbookProtection'] + +def unlockFile(fpath:str): + fname = os.path.basename(fpath) + fnamef, ftype = fname.rsplit(".",1) + + parent_path = os.path.dirname(fpath) + + tmpdir_path = os.path.join(parent_path, 'tmp') + copyed_tar_fpath = os.path.join(tmpdir_path, fname) + old_zip_fpath = tmpdir_path + '\\' + fnamef + '.zip' + extractalldir_path = os.path.join(tmpdir_path, fnamef) + new_zip_path = os.path.join(tmpdir_path, fnamef + '_removedPwd.zip') + new_zip_fnamef = os.path.basename(new_zip_path) + removedPwd_fpath = os.path.join(tmpdir_path, new_zip_fnamef + ftype) + new_fpath = os.path.join(parent_path, fnamef + '_removedPwd.' + ftype) + + try: + if os.path.exists(tmpdir_path): + os.remove(tmpdir_path) + + mkdir(tmpdir_path) + shutil.copyfile(fpath, copyed_tar_fpath) + os.rename(copyed_tar_fpath, old_zip_fpath) + + except FileExistsError as e: + raise Exception("文件已存在,无法创建") from e + except Exception as e: + raise Exception("拷贝 pptx 文件错误") from e + + # 解压文件 + unZip(old_zip_fpath, extractalldir_path) + + xmls = filterFiles(extractalldir_path, 'xml') + + for xml in xmls: + if('styles' not in xml and 'app' not in xml and 'core' not in xml and 'custom' not in xml): + for kwd in keyNode: + removeNode(xml, xml, kwd) + + zipDir(extractalldir_path, new_zip_path) # 重新压缩 + + try: # 重命名为 pptx,拷贝到原目录 + os.rename(new_zip_path, removedPwd_fpath) + shutil.copyfile(removedPwd_fpath, new_fpath) + except Exception as e: + raise Exception("拷贝文件错误") from e + + # 删除tmp下所有文件 + delDirs(tmpdir_path,root=True) + + +def removeNode(fpath:str, sfPath, keyNode:str): + """移除xml节点,并且存储 + + Args: + fpath (str): 源xml路径 + sfpath (str): 移除节点后的xml路径 + keyNode (str): 要移除节点 + """ + try: + tree = etree.parse(fpath) + + for child in tree.iter(): + if(keyNode in child.tag): + child.getparent().remove(child) + tree.write(sfPath) + break + except Exception as e: + raise Exception("移除节点失败") from e + + + + diff --git a/src/icon.ico b/src/icon.ico new file mode 100644 index 0000000..675f5eb Binary files /dev/null and b/src/icon.ico differ diff --git a/src/pdf.py b/src/pdf.py new file mode 100644 index 0000000..348ef71 --- /dev/null +++ b/src/pdf.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- +''' +@文件 :pdf.py +@时间 :2023/07/20 14:01:58 +@作者 :aliha +@版本 :1.0 +@依赖 :无 +@说明 :移除PDF限制密码 +''' + + +import pikepdf + + +def unlockFile(fpath:str): + """移除pdf限制编辑,并且存储 + + Args: + fpath (str): 带限制的pdf路径 + sfpath (str): 移除限制的pdf路径 + + Returns: + str: 移除成功的提示话语 + """ + try: + pdf = pikepdf.open(fpath, allow_overwriting_input=True) + except Exception as e: + print('打开pdf出错') + + try: + sfpath = fpath.rsplit('.',1)[0] +"_removepwd."+ fpath.rsplit('.',1)[1] + pdf.save(sfpath) + except Exception as e: + print('写入pdf失败') + + return 'ヾ(≧▽≦*)o 恭喜你,移除成功' diff --git a/src/pic.py b/src/pic.py new file mode 100644 index 0000000..b148304 --- /dev/null +++ b/src/pic.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- +''' +@文件 :pic.py +@时间 :2023/07/20 14:01:36 +@作者 :aliha +@版本 :1.0 +@依赖 :无 +@说明 :赞赏码的base64 +''' + + +imgstr = b'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' + + + diff --git a/src/pptx.py b/src/pptx.py new file mode 100644 index 0000000..308d3b1 --- /dev/null +++ b/src/pptx.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- +''' +@文件 :pptx.py +@时间 :2023/07/20 14:00:53 +@作者 :aliha +@版本 :1.0 +@依赖 :util.py +@说明 :移除PPTX限制密码 +''' + + +from lxml import etree +import shutil +import os +from util import delDirs, filterFiles, unZip, zipDir, mkdir + +keyNode = ['modifyVerifier'] + +def unlockFile(fpath:str): + fname = os.path.basename(fpath) + fnamef, ftype = fname.rsplit(".",1) + + parent_path = os.path.dirname(fpath) + + tmpdir_path = os.path.join(parent_path, 'tmp') + copyed_tar_fpath = os.path.join(tmpdir_path, fname) + old_zip_fpath = tmpdir_path + '\\' + fnamef + '.zip' + extractalldir_path = os.path.join(tmpdir_path, fnamef) + new_zip_path = os.path.join(tmpdir_path, fnamef + '_removedPwd.zip') + new_zip_fnamef = os.path.basename(new_zip_path) + removedPwd_fpath = os.path.join(tmpdir_path, new_zip_fnamef + ftype) + new_fpath = os.path.join(parent_path, fnamef + '_removedPwd.' + ftype) + + + try: + if os.path.exists(tmpdir_path): + os.remove(tmpdir_path) + + mkdir(tmpdir_path) + shutil.copyfile(fpath, copyed_tar_fpath) + os.rename(copyed_tar_fpath, old_zip_fpath) + + except FileExistsError as e: + raise Exception("文件已存在,无法创建") from e + except Exception as e: + raise Exception("拷贝 pptx 文件错误") from e + + + # 解压文件 + unZip(old_zip_fpath, extractalldir_path) + + xmls = filterFiles(extractalldir_path, 'xml') + + for xml in xmls: + if('Styles' not in xml and 'Props' not in xml and 'theme' not in xml and 'tag' not in xml and 'slide' not in xml): + for kwd in keyNode: + removeNode(xml, xml, kwd) + + zipDir(extractalldir_path, new_zip_path) # 重新压缩 + + try: # 重命名为 pptx,拷贝到原目录 + os.rename(new_zip_path, removedPwd_fpath) + shutil.copyfile(removedPwd_fpath, new_fpath) + except Exception as e: + raise Exception("拷贝文件错误") from e + + + # 删除tmp下所有文件 + delDirs(tmpdir_path,root=True) + + +def removeNode(fpath:str, sfPath, keyNode:str): + """移除xml节点,并且存储 + + Args: + fpath (str): 源xml路径 + sfpath (str): 移除节点后的xml路径 + keyNode (str): 要移除节点 + """ + try: + tree = etree.parse(fpath) + + for child in tree.iter(): + if(keyNode in child.tag): + child.getparent().remove(child) + tree.write(sfPath) + break + except Exception as e: + raise Exception("移除节点失败") from e + + + + + diff --git a/src/readme.py b/src/readme.py new file mode 100644 index 0000000..7218859 --- /dev/null +++ b/src/readme.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- +''' +@文件 :readme.py +@时间 :2023/07/20 14:00:28 +@作者 :aliha +@版本 :1.0 +@依赖 :无 +@说明 :软件的介绍说明 +''' + + +__updateLog = ''' + +

V 0.3.1

+

更新日期:2023-7-21

+

修复:错误路径导致程序卡死

+
+ +

V 0.3.0

+

更新日期:2023-7-20

+

新增:拖拽文件或者文件夹打开的功能

+

新增:批量移除限制密码的功能

+

变更:更改 GUI 框架为 Pyside6 ,更漂亮的 UI

+

修复:无法重复点击【开始处理】按钮,需要重新打开的 BUG

+
+ +

V 0.2.1

+

更新日期:2023-7-17

+

1. 增加移除限制 pptx 文档编辑的密码

+

2. 修复 bug :启动软件直接点击【开始】按钮会退出软件

+
+ +

V 0.2.0

+

更新日期:2023-7-13

+

1. 增加移除限制 xlsx 文档编辑的密码,包括工作簿和工作表保护密码

+
+ +

V 0.1.0

+

更新日期:2022-10-24

+

1. 移除限制pdf文档编辑的密码

+
+ +''' + +__info = """ +

批量移除限制编辑密码

+

移除PDF、xlsx、pptx限制密码输出文件在源路径,结果名称带_removepwd

+

只能移除文档限制编辑的密码解密不了加密文件

+""" + +info = { + 'author': 'aliha', + 'version': '0.3.1', + 'updateDate': '2023-07-21', + 'userWeb': 'https://www.52pojie.cn/home.php?mod=space&uid=1873109', + 'info': __info, + 'updateLog': __updateLog +} + +#

p标签设置字体颜色

+# nuitka --enable-plugin=pyside6 --standalone --onefile --remove-output --windows-disable-console --windows-icon-from-ico=icon.ico RemovePwd.py \ No newline at end of file diff --git a/src/removePwd.py b/src/removePwd.py new file mode 100644 index 0000000..4ebb1f3 --- /dev/null +++ b/src/removePwd.py @@ -0,0 +1,239 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- +''' +@文件 :removePwd.py +@时间 :2023/07/20 10:42:17 +@作者 :aliha +@版本 :1.0 +@依赖 :thread.py, styleSheet.py, readme.py, pic.py +@说明 :文档密码移除工具主界面 +''' + + +from PySide6.QtWidgets import QApplication, QLabel, QVBoxLayout, QWidget, QTabWidget, QPushButton, QHBoxLayout, QTextEdit, QTextBrowser, QSizePolicy, QSpacerItem +from PySide6.QtGui import QDragEnterEvent, QDropEvent, QDragMoveEvent, QPixmap, QPainter, QCursor, QCloseEvent, QFont +from PySide6.QtCore import Qt, QByteArray, QThread, Signal +import sys +import base64 +import os +from styleSheet import styleSheet +from readme import info +from pic import imgstr +from thread import WorkThread + +class FileDropLabel(QLabel): + def __init__(self, parent): + super().__init__(parent) + self.setObjectName("label") # 添加该行 + self.setAcceptDrops(True) + self.setAlignment(Qt.AlignCenter) + self.setText("拖拽文件或文件夹到这里") + self.setStyleSheet("QLabel { border: 2px dashed #aaa; padding: 5px; color: #555; }") + + def dragEnterEvent(self, event: QDragEnterEvent): + if event.mimeData().hasUrls(): + event.acceptProposedAction() + + def dragMoveEvent(self, event: QDragMoveEvent): + if event.mimeData().hasUrls(): + event.acceptProposedAction() + event.setDropAction(Qt.CopyAction) + pixmap = QPixmap(100, 100) + pixmap.fill(Qt.transparent) + painter = QPainter(pixmap) + painter.setOpacity(0.7) + painter.drawPixmap(0, 0, self.grab()) + painter.end() + cursor = QCursor(pixmap) + event.accept() + self.setCursor(cursor) + else: + event.ignore() + + def dropEvent(self, event: QDropEvent): + if event.mimeData().hasUrls(): + urls = event.mimeData().urls() + file_path = urls[0].toLocalFile() + self.setText("已选择: " + file_path) + self.setCursor(Qt.CursorShape.ArrowCursor) + # 调用MainWindow的方法,将选定的文件路径传递过去 + main_window = self.window() # 使用 window() 方法获取父级窗口(MainWindow) + if isinstance(main_window, MainWindow): + main_window.setSelectedFilePath(file_path) + else: + event.ignore() + +class ClickableLabel(QLabel): + def __init__(self, text, url=None): + super().__init__() + self.url = url + self.text = text + + if self.url is not None: + self.setText(f'{text}') + self.setOpenExternalLinks(True) # 打开链接时在外部浏览器中打开 + self.setStyleSheet("color: blue; text-decoration: underline;") # 设置颜色和下划线效果 + else: + self.setText(f'

{text}') + + font = QFont("Arial", 12, QFont.Bold) + self.setFont(font) + + + +class AboutUsTab(QWidget): + def __init__(self): + super().__init__() + + layout = QHBoxLayout(self) + left_layout = QVBoxLayout() + + # Create labels for displaying software information + author_label = ClickableLabel("作者信息:\t{}".format(info['author']),info['userWeb']) + version_label = ClickableLabel("软件版本信息:\t{}".format(info['version'])) + update_label = ClickableLabel("更新日期:\t{}".format(info['updateDate'])) + + # Create a layout for the QR code + qr_code_layout = QHBoxLayout() + qr_code_label = QLabel(self) + png = self.base64ToByte() + qr_code_image = QPixmap() + qr_code_image.loadFromData(png) + # qr_code_image = QPixmap("QR.png") + qr_code_image = qr_code_image.scaled(250, 250, Qt.KeepAspectRatio) + qr_code_label.setPixmap(qr_code_image) + qr_code_layout.addWidget(qr_code_label) + + left_layout.addWidget(author_label) + left_layout.addWidget(version_label) + left_layout.addWidget(update_label) + left_layout.addLayout(qr_code_layout) + left_layout.addStretch() + + funcInfo_label = QTextBrowser(self) + funcInfo_label.setOpenExternalLinks(True) + funcInfo_label.setLineWrapMode(QTextBrowser.WidgetWidth) + + func_info_html = """ +

功能简介:

+ {} +

更新日志

+ {} + """.format(info['info'],info['updateLog']) + + funcInfo_label.setHtml(func_info_html) + + layout.addLayout(left_layout) + layout.addWidget(funcInfo_label) + + self.setLayout(layout) + + def base64ToByte(self): + # Step 1: Decode the base64 data to obtain the raw image data + decoded_data = base64.b64decode(imgstr) + + # Step 2: Create a QByteArray from the decoded image data + byte_array = QByteArray(decoded_data) + + # Step 3: Load the image data into a QPixmap + # pixmap = QPixmap() + # pixmap.loadFromData(byte_array) + return byte_array + +class MainWindow(QWidget): + def __init__(self): + super().__init__() + self.setWindowTitle("文档密码移除工具") + self.resize(600, 280) + self.thread = None + self.selected_file_path = None + + # def rendererWindow(self): + layout = QVBoxLayout(self) + + tab_widget = QTabWidget(self) + + # Tab 1: Password Removal + tab1 = QWidget(self) + tab1_layout = QVBoxLayout(tab1) + label = FileDropLabel(tab1) + tab1_layout.addWidget(label) + + self.progress_output = QTextEdit(tab1) + self.progress_output.setReadOnly(True) + tab1_layout.addWidget(self.progress_output) + + self.button = QPushButton("开始处理", tab1) + self.button.clicked.connect(self.startWorkerThread) + tab1_layout.addWidget(self.button) + + tab1.setLayout(tab1_layout) + tab_widget.addTab(tab1, "限制密码移除") + + # Tab 2: Software Settings + tab2 = QWidget(self) + tab_widget.addTab(tab2, "批量加密解密") + + tab2_layout = QVBoxLayout(tab2) + development_label = QLabel("正在开发中,请耐心等待", tab2) + development_label.setAlignment(Qt.AlignCenter) + tab2_layout.addWidget(development_label) + + tab2.setLayout(tab2_layout) + + # Create the third tab (About Us) + tab3 = AboutUsTab() + tab_widget.addTab(tab3, "关于我们") + + layout.addWidget(tab_widget) + + self.setStyleSheet(styleSheet) + layout.setContentsMargins(0, 1, 0, 0) + self.setLayout(layout) + + def closeEvent(self, event: QCloseEvent) -> None: + return super().closeEvent(event) + + def startWorkerThread(self): + if self.selected_file_path is not None: + if os.path.isdir(self.selected_file_path) or os.path.isfile(self.selected_file_path): + self.worker = WorkThread() + self.thread = QThread() + self.worker.moveToThread(self.thread) + self.worker.setFilePath(self.selected_file_path) + self.worker.progressSignal.connect(self.updateProgressBar) + self.thread.started.connect(self.progress_output.clear) + self.thread.started.connect(self.worker.work) + self.thread.finished.connect(self.thread.quit) + self.thread.finished.connect(self.unlockStartButtom) + self.thread.finished.connect(self.thread.deleteLater) + self.thread.start() + self.button.setEnabled(False) + self.button.setStyleSheet('background-color: #e0e0e0;') + label = self.findChild(FileDropLabel, "label") + if label: + label.setEnabled(False) + else: + self.progress_output.clear() + self.progress_output.append('请输入正确的路径') + + def unlockStartButtom(self): + self.button.setEnabled(True) + self.button.setStyleSheet('background-color: #4caf50;') + label = self.findChild(FileDropLabel, "label") + if label: + label.setEnabled(True) + + def setSelectedFilePath(self, file_path): + self.selected_file_path = file_path + + def updateProgressBar(self, value): + self.progress_output.append(value) + + +if __name__ == '__main__': + app = QApplication(sys.argv) + window = MainWindow() + # window.rendererWindow() + window.show() + sys.exit(app.exec()) diff --git a/src/requirements.txt b/src/requirements.txt new file mode 100644 index 0000000..59fe6cc Binary files /dev/null and b/src/requirements.txt differ diff --git a/src/styleSheet.py b/src/styleSheet.py new file mode 100644 index 0000000..8d002bc --- /dev/null +++ b/src/styleSheet.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- +''' +@文件 :styleSheet.py +@时间 :2023/07/20 14:00:10 +@作者 :aliha +@版本 :1.0 +@依赖 :无 +@说明 :窗口的样式文件 +''' + + +styleSheet = """ +QPushButton { + background-color: #4caf50; + color: white; + padding: 10px; + border: none; + border-radius: 5px; +} +QPushButton:hover { + background-color: #45a049; +} +QPushButton:pressed { + background-color: #2980b9; +} +QTextEdit { + background-color: #fff; + border: 2px solid #aaa; + padding: 5px; + font-family: Arial, sans-serif; + font-size: 14px; + color: #333; +} +QTabWidget::pane { + border: 1px solid #aaa; + background-color: #f0f0f0; + padding: 0px; +} +QTabBar::tab { + background-color: #4caf50; + color: white; + padding: 8px; + border: none; + font-family: Arial, sans-serif; + font-size: 14px; + font-weight: bold; +} +QTabBar::tab:hover { + background-color: #45a049; +} +QTabBar::tab:selected { + background-color: #fff; + color: #4caf50; +} +""" diff --git a/src/thread.py b/src/thread.py new file mode 100644 index 0000000..7804e6e --- /dev/null +++ b/src/thread.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- +''' +@文件 :thread.py +@时间 :2023/07/20 10:41:04 +@作者 :aliha +@版本 :1.0 +@依赖 :excel.py, pdf.py, pptx.py +@说明 :移除密码的多线程处理 +''' + +from PySide6.QtCore import QObject, QThread, Signal +from pdf import unlockFile as pdfUnlock +from excel import unlockFile as xlsxUnlock +from pptx import unlockFile as pptxUnlock +import time +import os + +class WorkThread(QObject): + count = (0) + # countSignal = Signal(int) + progressSignal = Signal(str) + tipsSignal = Signal(str) + + def __init__(self): + super(WorkThread, self).__init__() + self.file_path = None + + def setFilePath(self, file_path): + self.file_path = file_path + + # def work(self): + # self.flag = True + # while self.flag: + # self.count += 1 + # self.progressSignal.emit(self.count) + # time.sleep(0.1) + # if(self.count == 100): + # QThread.currentThread().quit() + # break + + def work(self): + if os.path.isfile(self.file_path ): + self.progressSignal.emit('#=>[1/1]: {}'.format(self.file_path)) + self.unlockFile(self.file_path) + + if os.path.isdir(self.file_path ): + file_lists = os.listdir(self.file_path) + + for file in file_lists: + self.count += 1 + child_path = os.path.join(self.file_path, file) + + try: + self.unlockFile(child_path) + except Exception as e: + self.progressSignal.emit('捕获到异常信息: {}'.format(e)) + + self.progressSignal.emit('#=>[{}/{}]: {}'.format(self.count, len(file_lists), file)) + + self.progressSignal.emit('ヾ(≧▽≦*)o 恭喜你,移除成功 \r\n 解密的文件保存在原目录下哦,名称带“removedPwd') + QThread.currentThread().quit() + + + + def unlockFile(self, file): + try: + if('xlsx' in os.path.basename(file)): + xlsxUnlock(file) + if('pdf' in os.path.basename(file)): + pdfUnlock(file) + if('pptx' in os.path.basename(file)): + pptxUnlock(file) + + except Exception as e: + raise Exception("程序错误,请联系作者") from e + + +# 上述代码的启动方式如下: + +# class main(): + +# def runIt(self): +# self.worker = WorkThread() +# self.thread = QThread() +# self.worker.moveToThread(self.thread) +# self.worker.countSignal.connect(self.flush) +# self.thread.started.connect(self.worker.work) +# self.finished.connect(self.worker.quit) +# self.finished.connect(self.worker.deleteLater) +# self.thread.start() + +# def flush(self): +# print('flush ing') + + + diff --git a/src/util.py b/src/util.py new file mode 100644 index 0000000..6400fb4 --- /dev/null +++ b/src/util.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- +''' +@文件 :util.py +@时间 :2023/07/20 13:59:26 +@作者 :aliha +@版本 :1.0 +@依赖 :无 +@说明 :常用的文件处理的工具函数抽取到了这里 +''' + + +import shutil +import os +import zipfile + + +def delDirs(dirpath:str, root=False): + """删除路径文件下所有的文件,root=true 时包括根文件夹 + + Args: + dirpath (str): 文件夹路径 + root (boolean): 是否删除根目录 + """ + try: + filelists = os.listdir(dirpath) # 获取目录下所有文件列表 + for mydir in filelists: # 遍历文件列表 + filepath = os.path.join(dirpath, mydir) # 将文件名进行拼接 + if os.path.isfile(filepath): # 判断该文件是否为文件 + os.remove(filepath) # 若为文件,则直接删除 + elif os.path.isdir(filepath): # 判断该文件是否为文件夹 + shutil.rmtree(filepath, True) # 若为文件夹,则删除该文件夹及文件夹内所有文件 + if(root): + shutil.rmtree(dirpath, True) # 最后删除根文件夹 + except Exception as e: + print('删除缓存文件失败') + + +def filterFiles(folder_path:str, file_extension:str): + """获取指定路径下,符合扩展名条件的文件路径 + + Args: + folder_path (str): 根目录 + file_extension (str): 扩展名 + + Returns: + _type_: 查找结果组成的数组 + """ + + files = [] + + def filter(folder:str, extension:str): + + try: + file_lists = os.listdir(folder) + for child in file_lists: + child_path = os.path.join(folder, child) + + if(os.path.isfile(child_path)): + frname, ftype = os.path.basename(child_path).rsplit('.',1) + if(extension in ftype): + files.append(child_path) + continue + elif(os.path.isdir(child_path)): + filter(child_path, extension) + except Exception as e: + print('遍历文件错误') + raise e + + filter(folder_path, file_extension) + + return files + + +def unZip(zip_file:str, extractall_path:str): + """解压缩zip文件 + + Args: + zip_file (str): zip文件路径 + extractall_path (str): 解压路径 + """ + try: + if(zipfile.is_zipfile(zip_file)): + zin = zipfile.ZipFile(zip_file, 'r') # 以只读方式打开压缩包 + zin.extractall(path=extractall_path) + zin.close() + except Exception as e: + print('解压失败') + raise e + + +def zipDir(dirpath:str, outFullName:str): + """ + 压缩指定文件夹 + :param dirpath: 目标文件夹路径 + :param outFullName: 压缩文件保存路径+xxxx.zip + :return: 无 + """ + zip = zipfile.ZipFile(outFullName, "w", zipfile.ZIP_DEFLATED) + for path, dirnames, filenames in os.walk(dirpath): + # 去掉目标跟路径,只对目标文件夹下边的文件及文件夹进行压缩 + fpath = path.replace(dirpath, '') + + for filename in filenames: + zip.write(os.path.join(path, filename), os.path.join(fpath, filename)) + zip.close() + +def mkdir(dirpath:str): + try: + if( not os.path.exists(dirpath)): + os.makedirs(dirpath) + except Exception as e: + print('创建缓存文件错误') \ No newline at end of file