Python向tar/tar.gz添加文件后出现空文件问题求助
问题原因与解决方案
我之前也踩过这个坑!你遇到的问题核心在于手动创建的TarInfo对象缺少关键的size属性——tarfile模块完全不知道要从你的文件流里读取多少字节,所以默认只取了0字节,导致归档里的文件是空的。这个问题和gzip压缩无关,所以去掉:gz用普通tar文件也会出现同样的情况。
解决方案1:用gettarinfo()自动生成正确的TarInfo
如果你是操作本地文件,最简单的方式是用tarfile.TarFile.gettarinfo()方法自动获取文件的元信息(包括大小),这样就不用手动设置size了:
import tarfile # 创建测试文件 with open("testfile.txt", "w") as f: f.write("TESTTESTTEST") # 创建归档文件 with tarfile.open("archfile.tar.gz", "x:gz") as archive: with open("testfile.txt", 'rb') as f: # 自动获取文件的TarInfo,指定归档内的文件名 tar_info = archive.gettarinfo(fileobj=f, arcname="testfile.txt") # 注意:gettarinfo会将文件指针移到末尾,所以要重置到开头 f.seek(0) archive.addfile(tar_info, f) # 验证读取 with tarfile.open("archfile.tar.gz", "r:gz") as archive: print(archive.extractfile("testfile.txt").read()) # 输出 b'TESTTESTTEST'
或者更简单,直接用archive.add()方法一步到位:
with tarfile.open("archfile.tar.gz", "x:gz") as archive: archive.add("testfile.txt", arcname="testfile.txt")
解决方案2:手动设置TarInfo.size属性
如果你必须手动创建TarInfo(比如操作内存中的流),一定要记得设置size为流的实际字节长度:
针对本地文件
import tarfile import os # 创建测试文件 with open("testfile.txt", "w") as f: f.write("TESTTESTTEST") # 获取文件大小 file_size = os.path.getsize("testfile.txt") with tarfile.open("archfile.tar.gz", "x:gz") as archive: tar_info = tarfile.TarInfo("testfile.txt") tar_info.size = file_size # 关键:设置正确的文件大小 with open("testfile.txt", 'rb') as f: archive.addfile(tar_info, f) # 验证读取 with tarfile.open("archfile.tar.gz", "r:gz") as archive: print(archive.extractfile("testfile.txt").read())
针对内存中的字符串(你的最终目标)
注意:tarfile需要二进制流,所以要把字符串转成bytes,用io.BytesIO而不是io.StringIO:
import tarfile import io # 内存中的二进制内容 content = b"TESTTESTTEST" # 或者从字符串转:content = "TESTTESTTEST".encode('utf-8') stream = io.BytesIO(content) with tarfile.open("archfile.tar.gz", "x:gz") as archive: tar_info = tarfile.TarInfo("testfile.txt") tar_info.size = len(content) # 设置流的实际字节长度 stream.seek(0) # 确保流的指针在开头 archive.addfile(tar_info, stream) # 验证读取 with tarfile.open("archfile.tar.gz", "r:gz") as archive: print(archive.extractfile("testfile.txt").read()) # 输出 b'TESTTESTTEST'
总结
不管是本地文件还是内存流,只要你手动创建TarInfo对象,就必须指定正确的size属性——tarfile模块不会自动检测流的长度,只会按照TarInfo.size的值去读取字节。用gettarinfo()方法可以自动处理这些元信息,是更稳妥的选择。
内容的提问来源于stack exchange,提问作者dilaudid
相关产品推荐
相关产品推荐

