Как определить, сжат ли файл gzip?
У меня есть программа Python, которая собирается принимать текстовые файлы в качестве входных данных. Однако некоторые из этих файлов могут быть сжаты gzip.
Есть ли кроссплатформенный, используемый из Python способ определить, сжат ли файл gzip или нет?
Является ли следующий надежным, или обычный текстовый файл "случайно" может выглядеть как gzip, чтобы я мог получить ложные срабатывания?
try:
gzip.GzipFile(filename, 'r')
# compressed
# ...
except:
# not compressed
# ...
5 ответов
Магическое число для сжатых GZIP файлов 1f 8b
, Хотя тестирование для этого не является надежным на 100%, маловероятно, что "обычные текстовые файлы" начинаются с этих двух байтов - в UTF-8 это даже не разрешено законом.
Обычно сжатые файлы gzip имеют суффикс .gz
хоть. Четное gzip(1)
сам не распакует файлы без него, если вы --force
это к. Вы могли бы использовать это, но вам все равно придется иметь дело с возможным IOError (который вы должны в любом случае).
Одна проблема с вашим подходом заключается в том, что gzip.GzipFile()
не выдаст исключение, если вы передадите ему несжатый файл. Только позже read()
будут. Это означает, что вам, вероятно, придется реализовать некоторую логику вашей программы дважды. Некрасиво.
"Есть ли кроссплатформенный, используемый из Python способ определить, сжат ли файл gzip или нет?"
Принятый ответ дал мне 90% пути к довольно надежному решению (проверьте, если первые два байта 1f 8b
), но не показал, как на самом деле это сделать в Python. Вот один из возможных способов:
import binascii
def is_gz_file(filepath):
with open(filepath, 'rb') as test_f:
return binascii.hexlify(test_f.read(2)) == b'1f8b'
Что касается python3.7, это работает
import gzip
with gzip.open(input_file, 'r') as fh:
try:
fh.read(1)
except OSError:
print('input_file is not a valid gzip file by OSError')
Что касается python3.8, это также работает:
import gzip
with gzip.open(input_file, 'r') as fh:
try:
fh.read(1)
except gzip.BadGzipFile:
print('input_file is not a valid gzip file by BadGzipFile')
gzip
сама поднимет OSError
если это не сжатый файл.
>>> with gzip.open('README.md', 'rb') as f:
... f.read()
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "/Users/dennis/.asdf/installs/python/3.6.6/lib/python3.6/gzip.py", line 276, in read
return self._buffer.read(size)
File "/Users/dennis/.asdf/installs/python/3.6.6/lib/python3.6/gzip.py", line 463, in read
if not self._read_gzip_header():
File "/Users/dennis/.asdf/installs/python/3.6.6/lib/python3.6/gzip.py", line 411, in _read_gzip_header
raise OSError('Not a gzipped file (%r)' % magic)
OSError: Not a gzipped file (b'# ')
Можно объединить этот подход с некоторыми другими для повышения уверенности, например, проверка типа mime или поиск магического числа в заголовке файла (см. Другие ответы для примера) и проверка расширения.
import pathlib
if '.gz' in pathlib.Path(filepath).suffixes:
# some more inexpensive checks until confident we can attempt to decompress
# ...
try ...
...
except OSError as e:
...
Импортируйте модуль mimetypes. Он может автоматически угадать, какой у вас файл и сжимается ли он.
т.е.
mimetypes.guess_type('blabla.txt.gz')
возвращает:
('text / plain', 'gzip')
В Python3 не очень хорошо работает...
import mimetypes
filename = "./datasets/test"
def file_type(filename):
type = mimetypes.guess_type(filename)
return type
print(file_type(filename))
возвращает (None, None), но из команды unix "Файл"
: ~> наборы файлов / тестовые наборы данных /test: сжатые gzip данные, были "iostat_collection", из Unix, последнее изменение: чт 29 января 07:09:34 2015