web-dev-qa-db-ja.com

ファイルがgzip圧縮されているかどうかを確認するにはどうすればよいですか?

テキストファイルを入力として受け取るPythonプログラムがあります。ただし、これらのファイルの一部はgzipで圧縮されている場合があります。

ファイルがgzip圧縮されているかどうかを判断するために、Python)から使用できるクロスプラットフォームはありますか?

次の信頼できるものですか、それとも通常のテキストファイルが「誤って」gzipのように見えて、誤検知が発生する可能性がありますか?

try:
    gzip.GzipFile(filename, 'r')
    # compressed
    # ...
except:
    # not compressed
    # ...
22
Ryan Gabbard

マジックナンバー gzip圧縮ファイルの場合は_1f 8b_です。これをテストすることは100%信頼できるわけではありませんが、「通常のテキストファイル」がこれらの2バイトで始まる可能性はほとんどありません。UTF-8では合法ではありません。

通常、gzip圧縮ファイルには接尾辞_.gz_が付いています。 gzip(1)自体でさえ、_--force_しない限り、それなしではファイルを解凍しません。これを使用することも考えられますが、IOErrorの可能性に対処する必要があります(いずれの場合も対処する必要があります)。

このアプローチの問題の1つは、gzip.GzipFile()に非圧縮ファイルをフィードしても、例外がスローされないことです。後のread()だけがそうします。これは、おそらくプログラムロジックの一部を2回実装する必要があることを意味します。醜い。

36
user3850

「ファイルがgzip圧縮されているかどうかを判断するために、Pythonの方法から使用できるクロスプラットフォームはありますか?」

受け入れられた答えは、かなり信頼できるソリューション(最初の2バイトが1f 8bであるかどうかをテストする)への道の90%を取得しましたが、Pythonで実際にこれを行う方法を示していませんでした。これが1つの可能な方法です:

import binascii

def is_gz_file(filepath):
    with open(filepath, 'rb') as test_f:
        return binascii.hexlify(test_f.read(2)) == b'1f8b'
11

gzip自体は、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'# ')

このアプローチを他のアプローチと組み合わせて、mimetypeを確認したり、ファイルヘッダーでマジックナンバーを探したり(例については他の回答を参照)、拡張子を確認したりするなど、信頼性を高めることができます。

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:
     ...
2
Dennis

mimetypes モジュールをインポートします。それはあなたが持っているファイルの種類とそれが圧縮されているかどうかを自動的に推測することができます。

つまり.

mimetypes.guess_type('blabla.txt.gz')

戻り値:

( 'text/plain'、 'gzip')

0
David Ries

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')
0
winni2k

Python3ではうまく機能しないようです...

import mimetypes
filename = "./datasets/test"

def file_type(filename):
    type = mimetypes.guess_type(filename)
    return type
print(file_type(filename))

(None、None)を返しますが、unixコマンド「File」から

:〜>ファイルデータセット/テストデータセット/テスト:gzip圧縮データ、Unixの「iostat_collection」、最終更新日:Thu Jan 29 07:09:34 2015

0
ewr2san