本文为博主原创,未经许可严禁转载。
本文链接:https://blog.csdn.net/zyooooxie/article/details/114632112
最近在翻看Python的官方文档,https://docs.python.org/zh-cn/3.7/library/archiving.html ,做些分享;
【本文 实操是 用的 大小不超5M的文件】
个人博客:https://blog.csdn.net/zyooooxie
需求
- 对某文件、某文件list、某文件夹 压缩、解压
- 对某文件、某文件list、某文件夹 使用特定密码 压缩、解压
压缩
https://docs.python.org/zh-cn/3.7/library/zipfile.html
zipfile支持解密 ZIP归档中的加密文件,但是目前不能创建一个加密的文件。我的思路是 用命令行 调用本地EXE来加密压缩;【目前是用的7z;https://www.7-zip.org/】
def exe_zip(command_str: str):
"""
Run command:7z
:param command_str:
:return:
"""
# 使用7z;设置环境变量,加了Path
Log.info(command_str)
cp = subprocess.run(args=command_str, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding="utf-8")
print(cp.stdout)
Log.info(cp.returncode)
assert cp.returncode == 0
def write_one_file(file_path: str, zip_file_name: str, password: str = None):
"""
压缩一个文件
:param file_path:
:param zip_file_name:
:param password:
:return:
"""
Log.info('待压缩文件:{},密码:{}'.format(file_path, password))
if password is None:
# compression:写zip文档时 使用的压缩方法;
# mode:可选 r,w,a 代表不同的打开文件的方式;r 只读;w 重写\新建;a 添加;
# 要操作的zip文件大小超过2G,应该将allowZip64设置为True;
with zipfile.ZipFile(zip_file_name, mode='w', compression=zipfile.ZIP_DEFLATED) as zf:
# arcname 归档名称应当是基于归档根目录的相对路径,也就是说,它们不应以路径分隔符开头;
zf.write(file_path, arcname=os.path.basename(file_path))
else:
# zf.setpassword(password.encode()) # 是无法设置密码的
command_str = ' '.join(['7z', 'a', zip_file_name, '-p{}'.format(password), '{}'.format(file_path)])
exe_zip(command_str)
def write_many_files(file_path: list, zip_file_name: str, password: str = None):
"""
压缩多个文件
:param file_path:
:param zip_file_name:
:param password:
:return:
"""
Log.info('要压缩的文件list:{},密码:{}'.format(file_path, password))
if password is None:
with zipfile.ZipFile(zip_file_name, mode='w', compression=zipfile.ZIP_DEFLATED) as zf:
for f in file_path:
zf.write(f, arcname=os.path.basename(f))
else:
new_file_path = ' '.join(file_path)
print(new_file_path)
command_str = ' '.join(['7z', 'a', zip_file_name, '-p{}'.format(password), '{}'.format(new_file_path)])
exe_zip(command_str)
def write_folder(file_path: str or list, zip_file_name: str, password: str = None, zip_dirs: str = 'yes',
use_7z: str = 'no'):
"""
压缩一个文件夹;
有、无密码,7z都会保持原目录;
无密码时,zipfile可设置 是否保持原目录;
:param file_path:
:param zip_file_name:
:param password:
:param zip_dirs:
:param use_7z:
:return:
"""
Log.info('待压缩的目录:{},密码:{}'.format(file_path, password))
if password is None and use_7z == 'no':
with zipfile.ZipFile(zip_file_name, mode='w', compression=zipfile.ZIP_DEFLATED) as zf:
for root, dirs, files in os.walk(file_path):
# root 是 改变的
# print(root)
f_path = root.replace(file_path, '')
for f in files:
# print(os.path.join(root, f))
# print(os.path.join(f_path, f))
if zip_dirs == 'yes':
# 文件的全路径, 文件名 [多层目录]
zf.write(os.path.join(root, f), arcname=os.path.join(f_path, f))
else:
# 一层目录
zf.write(os.path.join(root, f), arcname=f)
else:
# -r 这个参数表示遍历所有的子目录,每个文件都执行压缩操作,添加到压缩文件中
# \* 该目录下的所有的文件
file_path += r'\*'
if password is None:
# 不使用密码
command_str = ' '.join(['7z', 'a', zip_file_name, '{}'.format(file_path)])
else:
# 使用密码
command_str = ' '.join(['7z', 'a', zip_file_name, '-p{}'.format(password), '{}'.format(file_path)])
exe_zip(command_str)
def test_write(file_path: str or list, password: str = None, encrypted_file_path: str = None):
"""
压缩文件
:param file_path:
:param password:
:param encrypted_file_path: 不要用中文路径
:return:
"""
zip_file_name = 'zy.zip'
if encrypted_file_path is not None:
zip_file_name = os.path.join(encrypted_file_path, zip_file_name)
if isinstance(file_path, list):
# 多个文件
write_many_files(file_path, zip_file_name, password)
elif os.path.isfile(file_path):
# 一个文件
write_one_file(file_path, zip_file_name, password)
elif os.path.isdir(file_path):
# 一个文件夹
# 无密码
# write_folder(file_path, zip_file_name, password) # zipfile 多层
# write_folder(file_path, zip_file_name, password, zip_dirs='no') # zipfile 一层
# write_folder(file_path, zip_file_name, password, use_7z='yes') # 7z 无密码
# 有密码
write_folder(file_path, zip_file_name, password, use_7z='yes') # 7z 有密码
# 压缩多个文件夹的场景,暂时没遇到
else:
raise Exception('file_path 不合法')
Log.info('压缩文件:{} 新建成功'.format(zip_file_name))
解压
def test_extractall_zipfile(encrypted_file_path: str, password: str = None, target_dir: str = None):
"""
zipfile解压
:param encrypted_file_path:
:param password:
:param target_dir:
:return:
"""
Log.info('待解压的 zip文件:{},密码:{}'.format(encrypted_file_path, password))
if zipfile.is_zipfile(encrypted_file_path):
with zipfile.ZipFile(encrypted_file_path, 'r') as zf:
Log.info('文件列表:{}'.format(zf.namelist()))
if target_dir is not None:
# `path' specifies a different directory to extract to.
if password is None:
zf.extractall(path=target_dir)
else:
zf.extractall(pwd=password.encode(), path=target_dir)
else:
# 当前工作目录
if password is None:
zf.extractall()
else:
zf.extractall(pwd=password.encode())
# 中文乱码【Windows系统】
# 修改zipfile的源码 decode('cp437')改为decode('gbk')
Log.info('解压文件夹:{} 解压成功'.format(target_dir))
def test_extractall_7z(encrypted_file_path: str, password: str = None, target_dir: str = None):
"""
7z解压
:param encrypted_file_path:
:param password:
:param target_dir:
:return:
"""
Log.info('待解压的 zip文件:{},密码:{}'.format(encrypted_file_path, password))
if zipfile.is_zipfile(encrypted_file_path):
if target_dir is None:
target_dir = os.path.abspath(os.getcwd())
if password is not None:
# x:将压缩档案中的所有文件解压到指定路径,压缩包内的文件所在的目录结构保持不变
# e:将压缩档案中的所有文件解压到指定路径,所有文件将输出到同一个目录中
# -aoa:直接覆盖现有文件,而没有任何提示
command_str = ' '.join(['7z', 'x', encrypted_file_path, '-p{}'.format(password), '-o{}'.format(target_dir), '-aoa'])
else:
command_str = ' '.join(['7z', 'x', encrypted_file_path, '-o{}'.format(target_dir), '-aoa'])
exe_zip(command_str)
Log.info('解压文件夹:{} 解压成功'.format(target_dir))
本文链接:https://blog.csdn.net/zyooooxie/article/details/114632112
交流技术 欢迎+QQ 153132336 zy
个人博客 https://blog.csdn.net/zyooooxie