Получить несжатый размер файла .gz в python - PullRequest
12 голосов
/ 10 ноября 2009

Используя gzip, tell () возвращает смещение в несжатом файле.
Чтобы показать индикатор выполнения, я хочу знать исходный (несжатый) размер файла.
Есть ли простой способ узнать?

Ответы [ 10 ]

16 голосов
/ 12 марта 2014

Несжатый размер сохраняется в последних 4 байтах gzip-файла. Мы можем прочитать двоичные данные и преобразовать их в int. (Это будет работать только для файлов размером менее 4 ГБ)

import struct

def getuncompressedsize(filename):
    with open(filename, 'rb') as f:
        f.seek(-4, 2)
        return struct.unpack('I', f.read(4))[0]
13 голосов
/ 10 ноября 2009

Формат gzip определяет поле с именем ISIZE, которое:

Содержит размер исходных (несжатых) входных данных по модулю 2 ^ 32.

В gzip.py , который, как я полагаю, используется вами для поддержки gzip, есть метод с именем _read_eof, определенный следующим образом:

def _read_eof(self):
    # We've read to the end of the file, so we have to rewind in order
    # to reread the 8 bytes containing the CRC and the file size.
    # We check the that the computed CRC and size of the
    # uncompressed data matches the stored values.  Note that the size
    # stored is the true file size mod 2**32.
    self.fileobj.seek(-8, 1)
    crc32 = read32(self.fileobj)
    isize = U32(read32(self.fileobj))   # may exceed 2GB
    if U32(crc32) != U32(self.crc):
        raise IOError, "CRC check failed"
    elif isize != LOWU32(self.size):
        raise IOError, "Incorrect length of data produced"

Там вы можете видеть, что поле ISIZE читается, но только для того, чтобы сравнить его с self.size для обнаружения ошибок. Тогда это должно означать, что GzipFile.size хранит фактический несжатый размер. Тем не менее, я думаю, что это не публично, поэтому вам, возможно, придется взломать его, чтобы разоблачить. Не уверен, извините.

Я только что посмотрел все это прямо сейчас, и я не пробовал, поэтому я могу ошибаться. Я надеюсь, что это вам пригодится. Извините, если я неправильно понял ваш вопрос.

4 голосов
/ 10 ноября 2009

Последние 4 байта .gz содержат оригинальный размер файла

4 голосов
/ 10 ноября 2009

Способ Unix: используйте "gunzip -l file.gz" через subprocess.call / os.popen, перехватывайте и анализируйте его вывод.

1 голос
/ 25 января 2019

Несмотря на то, что говорят другие ответы, последние четыре байта не являются надежным способом получения несжатой длины файла gzip. Во-первых, в файле gzip может быть несколько элементов, так что это будет только длина последнего элемента. Во-вторых, длина может быть больше 4 ГБ, и в этом случае последние четыре байта представляют длину по модулю 2 32 . Не длина.

Однако для того, что вы хотите, нет необходимости получать несжатую длину. Вместо этого вы можете основывать свой индикатор выполнения на количестве использованных input , по сравнению с длиной gzip-файла, который легко получить. Для типичных однородных данных этот индикатор выполнения будет отображать то же самое, что и индикатор выполнения, основанный вместо этого на несжатых данных.

1 голос
/ 23 августа 2017

Я не уверен насчет производительности, но этого можно достичь, не зная магию gzip, используя:

with gzip.open(filepath, 'rb') as file_obj:
    file_size = file_obj.seek(0, io.SEEK_END)

Это также должно работать для других (сжатых) потоковых ридеров, таких как bz2 или обычная open.

EDIT: как указано в комментариях, 2 во второй строке было заменено на io.SEEK_END, что определенно более читабельно и, вероятно, более перспективно для будущего.

EDIT: Работает только в Python 3.

1 голос
/ 15 марта 2011
    f = gzip.open(filename)
    # kludge - report uncompressed file position so progess bars
    # don't go to 400%
    f.tell = f.fileobj.tell
0 голосов
/ 10 января 2014
import gzip

File = gzip.open("input.gz", "r")
Size = gzip.read32(File)
0 голосов
/ 17 ноября 2009

GzipFile.size хранит несжатый размер, но он увеличивается только при чтении файла, поэтому вы должны предпочесть len (fd.read ()) вместо закрытого GzipFile.size.

0 голосов
/ 10 ноября 2009

Глядя на источник для модуля gzip, я вижу, что базовый файловый объект для GzipFile выглядит как fileobj. Итак:

mygzipfile = gzip.GzipFile()
...
mygzipfile.fileobj.tell()

?

Может быть, было бы неплохо сделать некоторую проверку работоспособности перед этим, например, проверить, существует ли атрибут с hasattr.

Не совсем публичный API, но ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...