如何使用Python tarfile库提取tar.gz.part*格式的分卷压缩文件
解决方案
实现原理
你使用split切割的是完整tar.gz压缩输出流,每个分卷仅为完整流的一部分,并非独立的gzip文件,所以单独读取单个分卷时要么因为流不完整报EOFError,要么读取后续分卷时因为没有gzip文件头报格式错误。必须按partaa→partab→partac的顺序将所有分卷拼接为连续的完整字节流后,才能正常解压。
普通实现(适合分卷总大小不超过内存的场景)
import tarfile import glob from io import BytesIO def extract_all_parts(part_prefix: str, extract_path: str): # 按名称排序自动得到aa/ab/ac的正确读取顺序 part_files = sorted(glob.glob(f"{part_prefix}*")) if not part_files: raise FileNotFoundError("未找到匹配的分卷文件") # 拼接所有分卷为完整字节流 full_stream = BytesIO() for part in part_files: with open(part, "rb") as f: full_stream.write(f.read()) full_stream.seek(0) # 用流模式打开压缩包解压 with tarfile.open(fileobj=full_stream, mode="r|gz") as tar: tar.extractall(path=extract_path) # 调用示例,公共前缀传入分卷文件名的公共部分即可 extract_all_parts(part_prefix="20210914.tar.gz.part", extract_path="tmp")
低内存占用实现(适合分卷总大小超过内存的场景)
不需要一次性加载所有分卷到内存,逐块读取拼接:
import tarfile import glob def generate_chunks(part_files): for part in part_files: with open(part, "rb") as f: # 每次读取1MB块,可根据需要调整大小 while chunk := f.read(1024 * 1024): yield chunk def extract_all_parts_low_memory(part_prefix: str, extract_path: str): part_files = sorted(glob.glob(f"{part_prefix}*")) if not part_files: raise FileNotFoundError("未找到匹配的分卷文件") # 实现适配tarfile读取要求的拼接流类 class ConcatenatedStream: def __init__(self, chunks): self.chunks = chunks self.buffer = b"" def read(self, size=-1): while size == -1 or len(self.buffer) < size: try: self.buffer += next(self.chunks) except StopIteration: break if size == -1: res = self.buffer self.buffer = b"" else: res = self.buffer[:size] self.buffer = self.buffer[size:] return res stream = ConcatenatedStream(generate_chunks(part_files)) with tarfile.open(fileobj=stream, mode="r|gz") as tar: tar.extractall(path=extract_path) # 调用示例 extract_all_parts_low_memory(part_prefix="20210914.tar.gz.part", extract_path="tmp")
内容的提问来源于stack exchange,提问作者Mr. Hobo
相关产品推荐
相关产品推荐

