import os ,shutil ,zipfile
class FileToZip():
def __init__(self):
self.volume_size = 95 * 1024 * 1024 # 分卷大小 95M
file_path = r'D:\test.txt'
zip_path = r'D:\test.zip'
status = '压缩文件'
if status == '压缩文件':
self.compress(file_path)
elif status == '解压文件':
self.decompress(zip_path)
# --------------------------------------------------压缩文件-------------------------------------------------
# 压缩文件
def compress(self ,file_path):
# 不压缩zip文件
if '.zip' in file_path:
return
# 获取文件名,或文件夹名
zip_name = self.get_file_name(file_path)
# 压缩为单个zip文件
with zipfile.ZipFile(f'{zip_name}.zip', 'w', zipfile.ZIP_DEFLATED) as zipf:
if os.path.isdir(file_path):
# 如果是目录,将目录及其内容压缩到 zip 文件中
self.zip_directory(file_path, zipf, file_path)
else:
# 如果是文件,直接将文件添加到 zip 文件中
zipf.write(file_path, os.path.basename(file_path))
# 分卷压缩
file_size = os.path.getsize(f'{zip_name}.zip')
if file_size > self.volume_size and self.volume_size != 0:
self.zip_part_compress(zip_name)
# 文件夹压缩
def zip_directory(self ,file_path ,zipf ,base_path=""):
for root, dirs, files in os.walk(file_path):
# 计算当前文件夹在 ZIP 中的相对路径
relative_path = os.path.relpath(root, base_path)
# 忽略根目录
if relative_path!= ".":
# 添加当前文件夹到 ZIP 文件中
zipf.write(root, arcname=relative_path)
# 添加当前文件夹中的所有文件到 ZIP 文件中
for file in files:
file_path = os.path.join(root, file)
relative_file_path = os.path.relpath(file_path, base_path)
zipf.write(file_path, arcname=relative_file_path)
# 分卷压缩
def zip_part_compress(self ,zip_name):
# 读取文件内容
with open(f'{zip_name}.zip', 'rb') as f:
data = f.read()
# 计算分卷数量
total_size = len(data)
num_volumes = (total_size + self.volume_size - 1) // self.volume_size
# 逐个写入分卷文件
for i in range(num_volumes):
# 计算分卷文件长度
start = i * self.volume_size
end = min(start + self.volume_size, total_size)
# 写入分卷文件
volume_data = data[start:end]
volume_filename = f"{zip_name}_part{i+1}.zip"
with open(volume_filename, 'wb') as vf:
vf.write(volume_data)
# 删除原压缩文件,只保留分卷文件
os.remove(f'{zip_name}.zip')
# 提取文件名,如果是文件夹,则返回文件夹名
def get_file_name(self ,path):
# 是否是文件夹
if os.path.isdir(path):
return os.path.basename(path)
base_name = os.path.basename(path)
return os.path.splitext(base_name)[0]
# --------------------------------------------------解压文件-------------------------------------------------
# 解压文件
def decompress(self ,zip_path):
# 只解压ZIP文件
if '.zip' not in zip_path:
return
# 根据压缩文件名和路径,创建文件夹
folder_path = self.createFolders(zip_path)
# 判断是否为分卷压缩,返回分卷文件路径列表
file_list = self.is_part_zip(zip_path)
if file_list:
# 构建临时zip文件路径
temp_zip = f'{os.path.dirname(zip_path)}\\temp.zip'
with open(temp_zip, 'ab') as output_zip:
# 逐个打开分卷文件并写入临时zip文件
for file_path in file_list:
with open(file_path, 'rb') as part_zip:
shutil.copyfileobj(part_zip, output_zip)
# 解压合并后的zip文件到folder_path
# 解码器优先级 判断是否为[utf-8] 否则使用[metadata_encoding] 未配置则使用[None = cp437]
with zipfile.ZipFile(zip_path ,'r' ,metadata_encoding="gbk") as full_zip:
full_zip.extractall(folder_path)
# 删除合并的zip文件
os.remove(temp_zip)
else:
# 直接解压ZIP文件到folder_path
# 解码器优先级 判断是否为[utf-8] 否则使用[metadata_encoding] 未配置则使用[None = cp437]
with zipfile.ZipFile(zip_path ,'r' ,metadata_encoding="gbk") as full_zip:
full_zip.extractall(folder_path)
# 判断是否为分卷ZIP文件
def is_part_zip(self ,zip_path):
base_name = os.path.basename(zip_path)
if 'part' not in base_name:
return False
# 同名前缀,[test_part1.zip],前缀为[test_part]
homonymPrefix = os.path.splitext(base_name)[0][0:-1]
file_list = []
# 获取路径中的目录
dir_name = os.path.dirname(zip_path)
# 遍历文件夹,获取同名前缀分卷文件
n = 1
for file_name in os.listdir(dir_name):
if '.zip' not in file_name:
continue
elif homonymPrefix in file_name:
file_list.append(f'{dir_name}\\{homonymPrefix}{n}.zip')
n += 1
return file_list
# 根据压缩文件名和路径,创建文件夹
def createFolders(self ,zip_path):
path = os.path.dirname(zip_path)
if '_part' in zip_path:
folder_name = os.path.basename(zip_path).split('_part')[0]
else:
folder_name = os.path.basename(zip_path).split('.zip')[0]
os.mkdir(path + '\\' + folder_name)
return path + '\\' + folder_name
if __name__ == "__main__":
FileToZip()
python 文件压缩与解压、包括分卷压缩与解压、文件夹压缩与解压
于 2023-12-28 10:46:50 首次发布