在 Python 中解压缩 .bz2 文件

Posted

技术标签:

【中文标题】在 Python 中解压缩 .bz2 文件【英文标题】:Decompressing a .bz2 file in Python 【发布时间】:2009-08-09 05:01:42 【问题描述】:

所以,这是一个看似简单的问题,但我显然非常非常沉闷。我有一个从网页下载所有 .bz2 文件的小脚本,但由于某种原因,该文件的解压缩让我非常头疼。

我是一个Python新手,所以答案可能很明显,请帮助我。

在这部分脚本中,我已经有了文件,我只想将它读出到一个变量中,然后解压缩?是对的吗?我已经尝试了各种方法来做到这一点,我通常在这个 sn-p 的最后一行得到“ValueError:找不到流的结尾”错误。我试图打开 zipfile 并以无数种不同的方式将其写入字符串。这是最新的。

openZip = open(zipFile, "r")
s = ''
while True:
    newLine = openZip.readline()
    if(len(newLine)==0):
       break
    s+=newLine
    print s                   
    uncompressedData = bz2.decompress(s)

嗨,Alex,我应该列出我尝试过的所有其他方法,因为我尝试过 read() 方式。

方法一:

print 'decompressing ' + filename

fileHandle = open(zipFile)
uncompressedData = ''

while True:            
    s = fileHandle.read(1024)
    if not s:
        break
        print('RAW "%s"', s)
        uncompressedData += bz2.decompress(s)

        uncompressedData += bz2.flush()

        newFile = open(steamTF2mapdir + filename.split(".bz2")[0],"w")
        newFile.write(uncompressedData)
        newFile.close()   

我得到错误:

uncompressedData += bz2.decompress(s)
ValueError: couldn't find end of stream

方法 B

zipFile = steamTF2mapdir + filename
print 'decompressing ' + filename
fileHandle = open(zipFile)

s = fileHandle.read()
uncompressedData = bz2.decompress(s)

同样的错误:

uncompressedData = bz2.decompress(s)
ValueError: couldn't find end of stream

非常感谢您的及时回复。我真的把我的头撞在墙上,因为无法解压缩一个简单的 .bz2 文件而感到非常沉重。

顺便说一句,使用7zip手动解压,以确保文件没有问题或任何东西,并且解压正常。

【问题讨论】:

你真的尝试过 Alex 的建议吗? 【参考方案1】:

您正在打开和读取压缩文件,就像它是由行组成的文本文件一样。不!不是。

uncompressedData = bz2.BZ2File(zipFile).read()

似乎更接近您的目标。

编辑:OP 展示了他尝试过的更多东西(尽管我没有看到任何关于尝试过最佳方法的说明——我在上面推荐的单线!)但他们似乎都有一个共同点,我重复上面的关键位:

打开...压缩文件好像 它是一个文本文件......它不是。

open(filename) 甚至更明确的open(filename, 'r') 打开并读取一个文本文件——压缩文件是一个二进制文件,所以为了正确阅读它,您必须使用open(filename, 'rb') 打开它。 (((我推荐的bz2.BZ2File当然知道它在处理压缩文件,所以没有必要再告诉它)。

在 Python 2.* 中,在 Unix-y 系统(即除 Windows 之外的所有系统)中,您可以随意使用 open(但在 Python 3.* 中则不能,因为文本是 Unicode , 而二进制是字节——不同的类型)。

在 Windows 中(以及在此之前的 DOS 中),区分始终是必不可少的,因为 Windows 的文本文件由于历史原因是特殊的(使用两个字节而不是一个字节来结束行,并且至少在某些情况下,取一个值'\0x1A'的字节作为文件的逻辑结尾),所以读写低级代码必须补偿。

所以我怀疑 OP 正在使用 Windows,并且正在为不小心使用 'rb' 选项(“读取二进制”)到内置的 open 付出代价。 (尽管bz2.BZ2File 仍然更简单,无论您使用什么平台!-)。

【讨论】:

嗨,Alex,感谢您的快速回复,请查看我的问题中针对您的评论进行的编辑。 所以这个方法的问题是,虽然它似乎解压得很好,但当我尝试运行它时,文件不知何故损坏了。当我使用 7zip 打开 .bz2 文件时,它运行良好。此外,正确提取的文件(使用 7zip)的大小为 948kb,而从我的脚本中提取的文件为 952KB。我完全感到困惑。 7zip 接受除 bz2 之外的许多其他格式,也许您的文件是其他格式之一。如果法律和隐私不妨碍这样做,把它放在一个公共 URL 上,给我 URL,我会让你知道它是什么格式以及如何解码它——没有手头的文件,基本上就是这样我做不到。 感谢您的所有帮助,Alex,抱歉在这里有点厚。这是有道理的,但是为什么 python bz2 库会解压缩文件呢?它不会抛出某种异常吗?我看看能不能找到放文件的地方(这不是违法的,它只是一个Team Fortress2地图文件(.bsp文件)的.bz2文件,但我不想把URL公开,因为它是我朋友的服务器托管它。如何检查 .bz2 文件是否实际上在 bz2 文件中? 但你说它确实引发了异常——ValueError!我相信你可以在bzip.org/downloads.html 下载一个仅限 bzip2 的可执行文件——如果该 exe 正确解码文件,我相信这应该证明它是一个 .bz2,反之亦然。【参考方案2】:

openZip = open(zipFile, "r")

如果您在 Windows 上运行,您可能需要在此处输入 openZip = open(zipFile, "rb"),因为该文件可能包含 CR/LF 组合,而您不需要'不希望他们被翻译。

newLine = openZip.readline()

正如 Alex 指出的那样,这是非常错误的,因为“行”的概念对于压缩流来说是陌生的。

s = fileHandle.read(1024) [...] uncompressedData += bz2.decompress(s)

出于同样的原因,这是错误的。 1024 字节的块对解压器来说意义不大,因为它需要使用自己的块大小。

s = fileHandle.read() uncompressedData = bz2.decompress(s)

如果不行,我会说是我上面提到的换行翻译问题。

【讨论】:

谢谢,这很有帮助。【参考方案3】:

这很有帮助。 在 Windows 打开时,2300 个文件中有 44 个给出了文件结尾丢失错误。 添加 b(inary) 标志来打开解决了这个问题。

for line in bz2.BZ2File(filename, 'rb', 10000000) :

效果很好。 (10M 是缓冲大小,适用于所涉及的大文件)

谢谢!

【讨论】:

以上是关于在 Python 中解压缩 .bz2 文件的主要内容,如果未能解决你的问题,请参考以下文章

AWS Lambda (Python) 无法在 S3 中解压缩和存储文件

如何在 Python3 中解压缩使用 PKZIP 以外的算法加密的文件?

6-压缩解压缩命令

Python:如何在 for 中解压缩多个值?

使用 pathlib 模块从 rglob() 方法的输出中解压缩所有项目 [关闭]

在应用函数中解压缩的值太多(python 2)