42 Stimmen

Wie kann man feststellen, ob eine Datei gzip-komprimiert ist?

Ich habe ein Python-Programm, das Textdateien als Eingabe verwenden soll. Einige dieser Dateien können jedoch gzip-komprimiert sein.

Gibt es eine plattformübergreifende, verwendbare von Python Weg zu bestimmen, ob eine Datei gzip komprimiert ist oder nicht?

Ist das Folgende zuverlässig, oder könnte eine gewöhnliche Textdatei "zufällig" so gzip-ähnlich aussehen, dass ich falsch positive Ergebnisse erhalte?

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

2 Stimmen

Nur ein kleiner Hinweis: Verlassen Sie sich niemals auf die Dateiendung. Wie man das macht, steht in Hops Antwort.

0 Stimmen

@Helper: Ich bin mir nicht sicher (siehe mein Edit). Sie müssten immer noch mit einem möglichen IOError umgehen, aber gzipped Dateien ohne das Suffix sind meiner Meinung nach kaputt schwere Entscheidung :)

48voto

themaninthewoods Punkte 780

Gibt es eine plattformübergreifende, verwendbare von Python Weg zu bestimmen, ob eine Datei gzip komprimiert ist oder nicht?

Le site akzeptierte Antwort erklärt, wie man eine gzip-komprimierte Datei im Allgemeinen erkennen kann: prüfen, ob die ersten beiden Bytes 1f 8b . Es wird jedoch nicht gezeigt, wie man es in Python implementiert.

Hier ist eine Möglichkeit:

def is_gz_file(filepath):
    with open(filepath, 'rb') as test_f:
        return test_f.read(2) == b'\x1f\x8b'

46voto

Le site magische Zahl für gzip-komprimierte Dateien ist 1f 8b . Obwohl die Tests hierfür nicht zu 100 % zuverlässig sind, ist es höchst unwahrscheinlich, dass "normale Textdateien" mit diesen beiden Bytes beginnen - in UTF-8 ist dies nicht einmal zulässig.

Normalerweise tragen gzip-komprimierte Dateien das Suffix .gz obwohl. Auch gzip(1) selbst entpackt keine Dateien ohne sie, es sei denn, Sie --force es zu. Sie könnten das verwenden, aber Sie müssten immer noch mit einem möglichen IOError umgehen (was Sie auf jeden Fall tun müssen).

Ein Problem mit Ihrem Ansatz ist, dass gzip.GzipFile() löst keine Ausnahme aus, wenn Sie es mit einer unkomprimierten Datei füttern. Nur eine spätere read() wird. Das bedeutet, dass Sie wahrscheinlich einen Teil Ihrer Programmlogik zweimal implementieren müssen. Hässlich.

15voto

winni2k Punkte 1342

Prüfung der magische Zahl einer gzip-Datei ist der einzig zuverlässige Weg. Seit Python 3.7 ist es jedoch nicht mehr nötig, sich selbst mit dem Vergleich von Bytes herumzuschlagen. Das gzip-Modul wird die Bytes für Sie vergleichen und eine Ausnahme auslösen, wenn sie nicht übereinstimmen!

Ab python3.7 funktioniert dies

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

Ab python3.8 funktioniert dies auch:

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

2voto

Dennis Punkte 51330

gzip selbst wird eine OSError wenn es sich nicht um eine gzipped-Datei handelt.

>>> 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'# ')

Sie können diesen Ansatz mit einigen anderen kombinieren, um die Sicherheit zu erhöhen, wie z. B. die Überprüfung des Mimetyps oder die Suche nach einer magischen Zahl im Header der Datei (siehe andere Antworten für ein Beispiel) und die Überprüfung der Erweiterung.

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

0voto

David Ries Punkte 99

Importieren Sie die Mimetypen Modul. Es kann automatisch erkennen, welche Art von Datei Sie haben und ob sie komprimiert ist.

d.h.

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

zurück:

('text/plain', 'gzip')

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X