压缩归档
# 压缩归档
zipfile/tarfile 打包压缩、密码保护 zip、分卷压缩、Shell tar/zip、内存流打包下载。
# 归档与压缩的区别
这是两个独立的概念,常被混淆:
- 归档(Archive):将多个文件合并为一个——
tar是典型归档格式,不压缩。 - 压缩(Compression):用算法减少数据体积——
gzip/bzip2/xz是压缩算法。
tar.gz = 先用 tar 归档,再用 gzip 压缩——两步串行。为什么不是"边归档边压缩"? 因为压缩算法依赖上下文(前文的重复模式才能压缩后续数据),单文件归档为整体后再压缩,压缩率最高。
压缩算法对比:gzip(DEFLATE)速度快、压缩率一般——适合日常场景;bzip2(Burrows-Wheeler)速度中等、压缩率更好——适合归档;xz(LZMA2)速度慢、压缩率最高——适合长期存储。Python tarfile 支持
w:gz/w:bz2/w:xz三种模式。
# 一、zipfile——ZIP 打包
ZIP 格式与 tar 的本质区别:ZIP 在文件内部维护索引表(Central Directory),允许随机访问单个文件——解压一个文件无需扫全包。tar 是流式格式,访问某文件必须从头扫描。
#!/usr/bin/env python3
import zipfile, os
from pathlib import Path
def create_zip(source_dir, output_path):
"""ZIP_DEFLATED = gzip 压缩算法"""
with zipfile.ZipFile(output_path, 'w', zipfile.ZIP_DEFLATED) as zf:
for f in Path(source_dir).rglob('*'):
if f.is_file():
zf.write(f, f.relative_to(source_dir)) # 相对路径避免绝对路径泄露
def extract_zip(zip_path, dest_dir='.'):
with zipfile.ZipFile(zip_path, 'r') as zf:
zf.extractall(dest_dir)
def create_encrypted_zip(source_dir, output_path, password):
"""⚠️ zipfile 的加密是传统 PKZIP(ZipCrypto)——AES-256 需第三方库"""
with zipfile.ZipFile(output_path, 'w', zipfile.ZIP_DEFLATED) as zf:
zf.setpassword(password.encode())
for f in Path(source_dir).rglob('*'):
if f.is_file(): zf.write(f, f.relative_to(source_dir))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 二、tarfile——tar 打包
tarfile 的 'r:*' 打开模式自动检测压缩格式——同一个接口解压 tar.gz/tar.bz2/tar.xz 无需区别对待。
#!/usr/bin/env python3
import tarfile, os
def create_tar(source_dir, output_path, mode='gz'):
mode_map = {'gz': 'w:gz', 'bz2': 'w:bz2', 'xz': 'w:xz'}
with tarfile.open(output_path, mode_map.get(mode, 'w:gz')) as tar:
tar.add(source_dir, arcname=os.path.basename(source_dir))
def extract_tar(tar_path, dest_dir='.'):
with tarfile.open(tar_path, 'r:*') as tar:
tar.extractall(path=dest_dir)
def list_tar(tar_path):
with tarfile.open(tar_path, 'r:*') as tar:
for m in tar.getmembers():
print(f" {m.name} ({m.size} bytes)")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 三、Shell 命令
#!/bin/bash
tar -czf backup.tar.gz dir/ # -c 创建 -z gzip -f 文件
tar -cJf backup.tar.xz dir/ # -J xz 压缩
tar -xzf backup.tar.gz # 解压
tar -tzf backup.tar.gz # -t 查看
tar -czf - dir/ | ssh user@host "tar -xzf - -C /dst/" # 管道直传
zip -r backup.zip dir/ # zip
unzip backup.zip
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 四、实战:内存流打包下载
io.BytesIO 流式打包的原理:tarfile 支持 fileobj 参数——可以将输出写入任何类文件对象(BytesIO/StringIO/socket),而非物理磁盘文件。对于 Web 多文件下载场景,这避免了两步操作(先写磁盘→再读取发送),直接流式输出到 HTTP Response。
#!/usr/bin/env python3
import tarfile, io, os
def tar_stream(paths):
"""打包到内存流——bytes 可直接用于 HTTP 响应"""
buf = io.BytesIO()
with tarfile.open(fileobj=buf, mode='w:gz') as tar:
for p in paths:
tar.add(p, arcname=os.path.basename(p))
return buf.getvalue()
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
上次更新: 2026/06/17, 12:47:39