【问题标题】:Read .tar.gz file in Python在 Python 中读取 .tar.gz 文件
【发布时间】:2016-09-25 06:42:00
【问题描述】:

我有一个 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'

还有,还有其他方法可以完成这项任务吗?

【问题讨论】:

标签: python file tar gzip


【解决方案1】:

docs 告诉我们,如果成员不是常规文件或链接,extractfile() 将返回 None

一种可能的解决方案是跳过 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()

【讨论】:

    【解决方案2】:

    如果成员既不是文件也不是链接,tarfile.extractfile() 可以返回 None。例如,您的 tar 存档可能包含目录或设备文件。修复:

    import tarfile
    import numpy as np 
    
    tar = tarfile.open("filename.tar.gz", "r:gz")
    for member in tar.getmembers():
         f = tar.extractfile(member)
         if f:
             content = f.read()
             Data = np.loadtxt(content)
    

    【讨论】:

      【解决方案3】:

      你可以试试这个

      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
      

      【讨论】:

      • 感谢代码 sn-p。您正在阅读两次 - 一次是设置“数据”变量,下一次是打印。你能改变你的代码来解决这个问题吗?
      【解决方案4】:

      您无法“读取”某些特殊文件(例如链接)的内容,但 tar 支持它们,并且 tarfile 可以正常提取它们。当tarfile 提取它们时,它不会返回类似文件的对象,而是返回 None。你得到一个错误,因为你的 tarball 包含这样一个特殊的文件。

      一种方法是在提取之前确定您正在处理的 tarball 中的条目的类型:有了这些信息,您可以决定是否可以“读取”文件。您可以通过调用 tarfile.getmembers() 返回 tarfile.TarInfos 来实现此目的,其中包含有关 tarball 中包含的文件类型的详细信息。

      tarfile.TarInfo 类具有确定 tar 成员类型所需的所有属性和方法,例如 isfile()isdir()tinfo.islnk()tinfo.issym() 然后相应地决定对每个成员做什么(是否提取等)。

      例如,我使用这些来测试this patched tarfile 中的文件类型,以跳过提取特殊文件并以特殊方式处理链接:

      for tinfo in tar.getmembers():
          is_special = not (tinfo.isfile() or tinfo.isdir()
                            or tinfo.islnk() or tinfo.issym())
      ...
      

      【讨论】:

        【解决方案5】:

        我的需求:

        1. Python3.
        2. 我的 tar.gz 文件由多个 utf-8 文本文件和目录组成。
        3. 需要从所有文件中读取文本行。

        问题:

        1. tar.getmembers() 返回的 tar 对象可能是None
        2. extractfile(fname) 返回的内容是字节 str(例如 b'Hello\t\xe4\xbd\xa0\xe5\xa5\xbd')。 Unicode 字符无法正确显示。

        解决方案:

        1. 首先检查 tar 对象的类型。我引用了 tarfile lib 的doc 中的示例。 (搜索“如何读取 gzip 压缩的 tar 存档并显示一些成员信息”)
        2. 从字节 str 解码为正常 str。 (ref - 投票最多的答案)

        代码:

        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}.")
        

        【讨论】:

        【解决方案6】:

        在 Jupyter 笔记本中,您可以执行以下操作

        !wget -c http://qwone.com/~jason/20Newsgroups/20news-bydate.tar.gz -O - | tar -xz
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-07-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-01-09
          • 1970-01-01
          相关资源
          最近更新 更多