可用io.TextIOWrapper包装zipfile.open()返回的字节流并指定encoding,再传给pandas.read_csv;pandas 1.1+也支持直接传BytesIO(f.read()),但大文件推荐前者。

用 zipfile 读取 ZIP 内文件,不落地直接喂给 pandas.read_csv
ZIP 包里有 data.csv,不想先解压到磁盘再读?完全可行。关键在于把 zipfile.ZipFile.open() 返回的类文件对象(支持 .read())转成 io.BytesIO 或直接传给 pandas.read_csv(后者从 pandas 1.1+ 开始原生支持二进制流)。
常见错误是直接传 zipfile.open() 的返回值,结果报 UnicodeDecodeError 或 EmptyDataError——因为 read_csv 默认期待文本流,而 ZipFile.open() 返回的是字节流。
- 正确做法:用
io.TextIOWrapper包一层,指定编码(如encoding='utf-8'),再传给read_csv - 更简洁做法:pandas 1.1+ 可直接接收
BytesIO,但需先.read()全部内容(小文件适用);大文件建议用TextIOWrapper流式处理 - 示例:
import zipfile import io import pandas as pd <p>with zipfile.ZipFile('data.zip') as z: with z.open('data.csv') as f:</p><h1>方式1:TextIOWrapper(推荐,内存友好)</h1><pre class="brush:php;toolbar:false;"><pre class="brush:php;toolbar:false;"> df = pd.read_csv(io.TextIOWrapper(f, encoding='utf-8')) # 方式2:BytesIO(适合小CSV) # df = pd.read_csv(io.BytesIO(f.read()))</code></pre></li>
读取 TAR 包里的 CSV,tarfile 配合 <code>pandas 的注意事项
TAR 不压缩时(.tar)或用 gzip/bzip2 压缩(.tar.gz、.tar.bz2)都可用 tarfile 模块,但接口比 zipfile 略繁琐:必须用 extractfile() 而非 open(),且返回对象不支持 .readline() ——这会导致 read_csv 的 chunksize 参数失效(报 UnsupportedOperation: seek)。
- 必须用
io.TextIOWrapper+encoding,不能依赖 pandas 自动解码 - 如果要分块读(
chunksize=1000),得先把整个文件读进BytesIO,再包装成文本流;否则会因底层tarfile.ExFileObject不支持随机 seek 而失败 - gzip 压缩的 TAR(
.tar.gz)无需额外解压,tarfile.open()自动识别,但注意模式参数:'r:gz'显式声明更稳妥 - 示例:
import tarfile import io import pandas as pd <p>with tarfile.open('data.tar.gz', 'r:gz') as t: f = t.extractfile('data.csv') if f is not None: df = pd.read_csv(io.TextIOWrapper(f, encoding='utf-8'))
read_csv 报错 OSError: Initializing from file failed 怎么办
这个错误通常出现在你误把 zipfile.ZipFile 或 tarfile.TarFile 对象本身传给了 read_csv(比如写成 pd.read_csv(z)),而不是它里面的成员文件。
立即学习“Python免费学习笔记(深入)”;
- 检查变量类型:打印
type(f),确认是zipfile.ZipExtFile或tarfile.ExFileObject,不是zipfile.ZipFile - ZIP 中文件名区分大小写,
z.open('DATA.CSV')在 Linux 下会失败,而 Windows ZIP 工具常默认存小写名 - TAR 中路径含前导
./或绝对路径(如/home/user/data.csv)时,extractfile()可能返回None,务必判空 - 用
z.namelist()或t.getnames()先确认目标文件是否存在、路径是否精确匹配
性能与内存:大压缩包里读单个 CSV 文件的优化点
当 ZIP/TAR 体积达百 MB 以上,但只读其中一个小 CSV,别调用 extractall() 或遍历全部成员——浪费 I/O 和内存。
- ZIP:用
z.getinfo(name)快速定位,避免扫描全表;z.open()是惰性读取,只加载目标文件内容 - TAR:用
t.getmember(name)替代循环t.getmembers(),尤其对含数千文件的包 - 若 CSV 含中文且编码不确定,别用
chardet全文件检测(会强制读完整个文件);改用z.open()读前 1KB +chardet.detect(),再重新 open - 真正的大文件(>100MB CSV)建议先解压到临时目录再读,避免流式解析过程中 ZIP/TAR 解压缓冲区反复切换上下文
实际用的时候,最易被忽略的是编码和流类型匹配——字节流不包装就喂给 read_csv,十次有九次报错;还有就是 TAR 成员路径的隐式前缀问题,看着文件存在,extractfile() 却返回 None。


















