Python中TarFile.extractall自动添加子目录的路径问题求助
tar包提取自动生成额外目录的原因与解决方法
问题描述
我编写了一段下载并提取数据集的代码,问题出在extractall()这一行:
housing_tarball.extractall(path='datasets')
- 设置
path='dataset'时,文件被提取到/dataset/housing目录; - 设置
path='dataset/housing/'时,文件被提取到/dataset/housing/housing目录;
代码会自动添加housing目录,但我并未在path中指定,想知道这是否与tar包的存储路径tarball_path = Path("datasets/housing/housing.tgz")有关?
完整代码
from pathlib import Path import pandas as pd import tarfile import urllib.request import os def load_housing_data(): tarball_path = Path("datasets/housing/housing.tgz") if not tarball_path.is_file(): Path("datasets/housing").mkdir(parents=True, exist_ok=True) # 创建目录(如果不存在) url = "https://github.com/ageron/data/raw/main/housing.tgz" with urllib.request.urlopen(url) as response, tarball_path.open(mode="wb") as tarball_file: # 以二进制写入模式打开文件 tarball_file.write(response.read()) # 将响应内容写入文件 with tarfile.open(tarball_path) as housing_tarball: # 打开tar包 housing_tarball.extractall(path='datasets') # 将所有文件提取到datasets目录 # 删除tar包文件 os.remove(tarball_path) return pd.read_csv("datasets/housing/housing.csv")
解答
这个问题和tar包的存储路径完全无关,核心原因是你下载的housing.tgz压缩包内部本身就包含一个housing目录,housing.csv文件就放在这个目录里。tarfile.extractall()的默认行为是完全还原压缩包内的目录结构,所以不管你指定什么path,都会把压缩包里的housing目录连同里面的文件一起解压到目标路径下。
解决方法
有两种常用的处理方式:
方法1:解压后调整文件路径
解压完成后,把目标文件移动到你想要的位置,再删除多余的目录:
import shutil # 解压后执行以下代码 shutil.move("datasets/housing/housing.csv", "datasets/housing.csv") shutil.rmtree("datasets/housing") # 删除空的子目录
方法2:直接提取单个文件并修改路径(更高效)
如果只需要housing.csv,可以跳过解压整个包,直接提取目标文件并修改它的存储路径,去掉外层的housing目录:
with tarfile.open(tarball_path) as housing_tarball: # 获取压缩包内的csv文件成员 csv_member = housing_tarball.getmember("housing/housing.csv") # 修改成员的名称,去掉外层的housing目录 csv_member.name = "housing.csv" # 提取到指定目录 housing_tarball.extract(csv_member, path='datasets')
修改后的完整代码
用方法2优化后的代码如下:
from pathlib import Path import pandas as pd import tarfile import urllib.request import os def load_housing_data(): tarball_path = Path("datasets/housing/housing.tgz") if not tarball_path.is_file(): Path("datasets/housing").mkdir(parents=True, exist_ok=True) url = "https://github.com/ageron/data/raw/main/housing.tgz" with urllib.request.urlopen(url) as response, tarball_path.open(mode="wb") as tarball_file: tarball_file.write(response.read()) with tarfile.open(tarball_path) as housing_tarball: # 直接提取csv文件并调整路径 csv_member = housing_tarball.getmember("housing/housing.csv") csv_member.name = "housing.csv" housing_tarball.extract(csv_member, path='datasets') os.remove(tarball_path) # 删除临时创建的空目录 try: os.rmdir(Path("datasets/housing")) except OSError: pass return pd.read_csv("datasets/housing.csv")
内容的提问来源于stack exchange,提问作者user16497397
相关产品推荐
相关产品推荐

