正确区分压缩的.gz文件和存档的tar.gz文件?

时间:2016-08-23 23:03:19

标签: python compression archive python-magic

处理区分gzip或bzip2格式的普通压缩文件(例如.gz)和使用gzip或bzip2压缩的tarball(例如.tar.gz)的正确方法是什么?使用后缀扩展的标识不是一个可靠的选项,因为它可能的文件可能最终被重命名。

现在在命令行上我能够做到这样的事情:

bzip2 -dc test.tar.bz2 |head|file -

所以我尝试使用以下函数在python中尝试类似的东西:

def get_magic(self, store_file, buffer=False, look_deeper=False):
    # see what we're indexing
    if look_deeper == True:
        m = magic.Magic(mime=True, uncompress=True)
    else:
        m = magic.Magic(mime=True) 

    if buffer == False:
        try:
            file_type = m.from_file(store_file)

        except Exception, e:
            raise e

    else:
        try:
            file_type = m.from_buffer(store_file)

        except Exception, e:
            raise e

    return file_type 

然后,在尝试读取压缩的tarball时,我将通过以下方式从其他地方传入缓冲区:

    file_buffer = open(file_name).read(8096) 
    archive_check = self.get_magic(file_buffer, True, True)

不幸的是,使用python-magic中的 uncompress 标志会出现问题,因为看起来python-magic希望我传入整个文件,即使我只想让它读取缓冲区。我最终得到了例外:

bzip2 ERROR: Compressed file ends unexpectedly

看到我正在查看的文件最终可能 2M到20GB 这会变得相当成问题。我不想阅读整个文件

是否可以将其破解并将压缩文件的末尾关闭并将其附加到缓冲区?最好忽略使用python-magic解压缩文件的想法,而是在我传入缓冲区来识别通过之前执行此操作:

    file_buffer = open(file_name, "r:bz2").read(8096) 

有更好的方法吗?

2 个答案:

答案 0 :(得分:0)

如果未处理的数据完全是1024个零字节(空的tar文件),那么偏移量为257的未压缩数据为“ustar”,时,很可能是tar文件。

您可以使用z = zlib.decompressobj()z = bz2.BZ2Decompressor()z.decompress()只读取未压缩数据的前1024个字节。

答案 1 :(得分:0)

我实际上要将Mark的答案标记为正确答案,因为它给了我提示。

我最终倾销了这个项目做了六个月的其他事情,并且因为bz2.BZ2Decompressor似乎没有按照预期的那样做而难倒。事实证明,这个问题在1024字节内无法解决。

#!/usr/bin/env python

import os
import bz2
import magic

store_file = "10mb_test_file.tar.bz2"
m = magic.Magic(mime=True)

file_buffer = open(store_file, "rb").read(1000000)
buffer_chunk = ""

decompressor = bz2.BZ2Decompressor()
print ( "encapsulating bz2" )
print ( type(file_buffer) )
print ( len(file_buffer) )
file_type = m.from_buffer(file_buffer)
print ( "file type: %s :" % file_type)

buffer_chunk += decompressor.decompress( file_buffer )
print ( "compressed file contents" )
print ( type(buffer_chunk) )
print ( len(buffer_chunk) )

file_type = m.from_buffer(buffer_chunk)
print ( "file type: %s :" % file_type)

奇怪的是,使用20MB的tar.bz2文件,我可以使用200,000字节而不是1,000,000字节的值,但是这个值对10MB测试文件不起作用。我不知道它是否特定于所涉及的tar.bz2存档,我没有查看所涉及的算法,看看它们是否处于特定点,但到目前为止读取大约10MB的数据似乎对每个存档文件起作用到5GB。 open()。read(缓冲区)将读取缓冲区或EOF的大小,这样就可以了。