我有一个 25GB 的文本文件。所以我将其压缩为 tar.gz,它变成了 450 MB。现在我想从 python 读取该文件并处理文本数据。为此我提到了question。但就我而言,代码不起作用。代码如下:
import tarfile
import numpy as np
tar = tarfile.open("filename.tar.gz", "r:gz")
for member in tar.getmembers():
f=tar.extractfile(member)
content = f.read()
Data = np.loadtxt(content)
错误如下:
Traceback (most recent call last):
File "dataExtPlot.py", line 21, in <module>
content = f.read()
AttributeError: 'NoneType' object has no attribute 'read'
还有其他方法可以完成这项任务吗?
docs 告诉我们,如果成员不是常规文件或链接,则 extractfile() 返回 None。
一种可能的解决方案是跳过“无”结果:
tar = tarfile.open("filename.tar.gz", "r:gz")
for member in tar.getmembers():
f = tar.extractfile(member)
if f is not None:
content = f.read()
t = tarfile.open("filename.gz", "r")
for filename in t.getnames():
try:
f = t.extractfile(filename)
Data = f.read()
print filename, ':', Data
except :
print 'ERROR: Did not find %s in tar archive' % filename
Python3.
utf-8
tar.getmembers() 返回的 tar 对象可能是
None
extractfile(fname)
首先检查 tar 对象的类型。我参考了 tarfile lib 的 代码:
with tarfile.open("sample.tar.gz", "r:gz") as tar:
for tarinfo in tar:
logger.info(f"{tarinfo.name} is {tarinfo.size} bytes in size and is: ")
if tarinfo.isreg():
logger.info(f"Is regular file: {tarinfo.name}")
f = tar.extractfile(tarinfo.name)
# To get the str instead of bytes str
# Decode with proper coding, e.g. utf-8
content = f.read().decode('utf-8', errors='ignore')
# Split the long str into lines
# Specify your line-sep: e.g. \n
lines = content.split('\n')
for i, line in enumerate(lines):
print(f"[{i}]: {line}\n")
elif tarinfo.isdir():
logger.info(f"Is dir: {tarinfo.name}")
else:
logger.info(f"Is something else: {tarinfo.name}.")
tarfile
提取它们时,它不会返回类似文件的对象,而是返回 None。你会得到一个错误,因为你的 tarball 包含这样一个特殊的文件。
一种方法是在提取 tarball 之前确定您正在处理的 tarball 中的条目类型:有了这些信息,您可以决定是否可以“读取”该文件。您可以通过调用
tarfile.getmembers()
返回
tarfile.TarInfo
来实现此目的,其中包含有关 tarball 中包含的文件类型的详细信息。 tarfile.TarInfo
类具有确定 tar 成员类型所需的所有属性和方法,例如
isfile()
或 isdir()
或 tinfo.islnk()
或 tinfo.issym()
,然后相应地决定对每个成员执行什么操作(摘录或不,等等)。例如,我使用这些来测试此修补的 tarfile
中的文件类型,以跳过提取特殊文件并以特殊方式处理链接:
for tinfo in tar.getmembers():
is_special = not (tinfo.isfile() or tinfo.isdir()
or tinfo.islnk() or tinfo.issym())
...
tar = tarfile.open(tar_archive, 'r:gz')
files = tar.getmembers()
seqs_file = tar.extractfile(files[0])
seqs_file = gzip.open(seqs_file, 'rt')
content = seqs_file.readlines()
我认为如果你有更多文件,你可以循环并使用 gzip.open 将它们一一打开,但我没有测试。我希望这个解决方案对其他人有用。
!wget -c http://qwone.com/~jason/20Newsgroups/20news-bydate.tar.gz -O - | tar -xz