2012-10-24 10 views
18

Eine komprimierte Datei kann in folgende logische Gruppen eingeteilt werden:
a. Das Betriebssystem, an dem Sie arbeiten (* ix, Win) usw.
b. Verschiedene Arten von Komprimierungsalgorithmen (z. B. .zip, .Z, .bz2, .rar, .gzip). Nicht zuletzt aus einer Standardliste meist verwendeter komprimierter Dateien.
c. Dann haben wir Tar Ball Mechanismus - wo ich vermute, es gibt keine Kompression. Aber es wirkt eher wie eine Verkettung.Python - Mechanismus zum Identifizieren komprimierter Dateitypen und zum Dekomprimieren

Nun, wenn wir beginnen, die oben genannten Satz von komprimierten Dateien zu adressieren,
a. Option (a) würde von python beachtet werden, da es plattformunabhängige Sprache ist.
b. Option (b) und (c) scheint ein Problem zu haben.

Was benötige ich
Wie kann ich den Dateityp (Kompressionstyp) zu identifizieren und sie dann UN komprimieren?


Like:

fileType = getFileType(fileName) 
switch(fileType): 
case .rar: unrar.... 
case .zip: unzip.... 

etc 

So ist die grundlegende Frage ist, wie identifizieren wir den Kompressionsalgorithmus auf der Datei basiert (vorausgesetzt, dass die Erweiterung nicht oder nicht korrekt zur Verfügung gestellt)? Gibt es einen bestimmten Weg, um es in Python zu tun?

Antwort

26

This page hat eine Liste von "magischen" Dateisignaturen. Ergreifen Sie die, die Sie brauchen, und legen Sie sie in ein Diktat wie unten. Dann brauchen wir eine Funktion, die den dict keys mit dem Start der Datei übereinstimmt.Ich habe einen Vorschlag geschrieben, obwohl er durch Vorverarbeitung des magic_dict in z.B. ein Riese kompiliert Regexp.

magic_dict = { 
    "\x1f\x8b\x08": "gz", 
    "\x42\x5a\x68": "bz2", 
    "\x50\x4b\x03\x04": "zip" 
    } 

max_len = max(len(x) for x in magic_dict) 

def file_type(filename): 
    with open(filename) as f: 
     file_start = f.read(max_len) 
    for magic, filetype in magic_dict.items(): 
     if file_start.startswith(magic): 
      return filetype 
    return "no match" 

Diese Lösung sollte Cross-Plattform sein und ist natürlich nicht abhängig von der Dateinamenerweiterung, aber es kann zu Fehlalarmen für Dateien mit zufälligem Inhalt geben, die nur mit einigem spezifischen magischen Bytes passieren zu starten.

+0

Dies identifiziert den Dateityp. Sie sollten jedoch ein Objekt zurückgeben, das durch Öffnen der Datei und Erlauben des Zugriffs erstellt wurde. Andernfalls werden Sie den Dateityp erneut testen, um zu sehen, ob Sie ihn verarbeiten sollten. Dies kann vermieden werden, indem eine allgemeine Abstraktion erstellt wird, die mit allen unterstützten Dateitypen umgehen kann. Das Muster lautet "Fabrik". – Ber

+0

Sie können diese Seite auch verwenden, um nach den gewünschten Signaturen zu suchen: http://www.filesignigns.net/index.php –

+0

Das zip-Dateiformat erlaubt es, beliebige Daten an den Anfang der Datei anzuhängen, also nach a zu suchen magische Zahl für Zip-Dateien ist nicht in allen Fällen korrekt. –

0

"a" ist völlig falsch.

"b" kann leicht schlecht interpretiert werden, da ".zip" nicht bedeutet, dass die Datei tatsächlich eine Zip-Datei ist. Es könnte ein JPEG mit Zip-Erweiterung sein (für verwirrende Zwecke, wenn Sie möchten).

Sie müssen tatsächlich überprüfen, ob die Daten in der Datei mit den Daten übereinstimmen, die von der Erweiterung erwartet werden. Schauen Sie sich auch magic byte.

+0

Mit Option (a), ich meinte nur Code geschrieben in Python zum Unkomprimieren sagen Unix, muss für die gleiche Datei un-Komprimierung in WIN arbeiten. Irgendein bestimmter Grund, dass ich falsch liege? –

+1

Ein Komprimierungsalgorithmus ist OS-unabhängig. Sie können eine Datei in Unix komprimieren, dann auf Windows dekomprimieren, dann an einen Mac senden und erneut komprimieren, die komprimierte Datei von Unix und die von Mac vergleichen und sie werden ein bisschen ein bisschen gleich sein. – alexandernst

+0

@kumar_m_kiran Im Allgemeinen (am wahrscheinlichsten) können Sie den gleichen Python-Code verwenden, um eine Datei über das Betriebssystem mit Python zu dekomprimieren. Sie wollten klassifizieren basierend auf dem Python-Code, der für die Dekomprimierung auf verschiedenen Betriebssystemen benötigt wird (was die Plattformunabhängigkeit mit sich bringt) mit dem (falschen) Verständnis, dass verschiedene Betriebssysteme einen anderen Python-Code benötigen (was im Allgemeinen nicht wahr ist). Du hast es aber mit einer Wortwahl gesagt, die etwas anderes bedeutet und dich alexandernst korrigiert hat. – abc

3

Dies ist eine komplexe Frage, die von einer Reihe von Faktoren abhängt: Die wichtigste ist, wie tragbar Ihre Lösung sein muss.

Die Grundlagen hinter dem Finden des Dateityps bei einer Datei ist es, einen identifizierenden Header in der Datei zu finden, normalerweise "magic sequence" or signature header, der angibt, dass eine Datei einen bestimmten Typ hat. Der Name oder die Erweiterung wird normalerweise nicht verwendet, wenn sie vermieden werden kann. Für einige Dateien hat Python dies eingebaut. Um beispielsweise mit .tar Dateien umzugehen, können Sie das Modul tarfile verwenden, das eine bequeme Methode is_tarfile hat. Es gibt ein ähnliches Modul mit dem Namen zipfile. Mit diesen Modulen können Sie auch Dateien in reinem Python extrahieren.

Zum Beispiel:

f = file('myfile','r') 
if zipfile.is_zipfile(f): 
    zip = zipfile.ZipFile(f) 
    zip.extractall('/dest/dir') 
elif tarfile.is_tarfile(f): 
    ... 

Wenn Ihre Lösung Linux oder OSX nur ist, gibt es auch die file Befehl, der einen großen Teil der Arbeit für Sie tun. Sie können die integrierten Tools auch verwenden, um die Dateien zu dekomprimieren. Wenn Sie nur ein einfaches Skript ausführen, ist diese Methode einfacher und bietet Ihnen eine bessere Leistung.

13

Basierend auf lazyr Antwort und meinen Kommentar, hier ist das, was ich meine:

class CompressedFile (object): 
    magic = None 
    file_type = None 
    mime_type = None 
    proper_extension = None 

    def __init__(self, f): 
     # f is an open file or file like object 
     self.f = f 
     self.accessor = self.open() 

    @classmethod 
    def is_magic(self, data): 
     return data.startswith(self.magic) 

    def open(self): 
     return None 

import zipfile 

class ZIPFile (CompressedFile): 
    magic = '\x50\x4b\x03\x04' 
    file_type = 'zip' 
    mime_type = 'compressed/zip' 

    def open(self): 
     return zipfile.ZipFile(self.f) 

import bz2 

class BZ2File (CompressedFile): 
    magic = '\x42\x5a\x68' 
    file_type = 'bz2' 
    mime_type = 'compressed/bz2' 

    def open(self): 
     return bz2.BZ2File(self.f) 

import gzip 

class GZFile (CompressedFile): 
    magic = '\x1f\x8b\x08' 
    file_type = 'gz' 
    mime_type = 'compressed/gz' 

    def open(self): 
     return gzip.GzipFile(self.f) 


# factory function to create a suitable instance for accessing files 
def get_compressed_file(filename): 
    with file(filename, 'rb') as f: 
     start_of_file = f.read(1024) 
     f.seek(0) 
     for cls in (ZIPFile, BZ2File, GZFile): 
      if cls.is_magic(start_of_file): 
       return cls(f) 

     return None 

filename='test.zip' 
cf = get_compressed_file(filename) 
if cf is not None: 
    print filename, 'is a', cf.mime_type, 'file' 
    print cf.accessor 

jetzt können die komprimierten Daten cf.accessor mit zuzugreifen. Alle Module stellen ähnliche Methoden wie 'read()', 'write()', etc. zur Verfügung.

+0

in get_compressed_file Funktion Sie tun cls (f), f ist ein Dateihandler, während Ihre offenen Funktionen erwarten Dateinamen ... Ich habe es geändert, um f zu schließen, und übergeben Sie stattdessen den Dateinamen. Gibt es einen besseren Weg? – fransua

+0

mein vorheriger Kommentar kann zu Python-Version ... in python2 verwandt werden bz2.BZ2File akzeptiert nur Zeichenfolge – fransua

0

Wenn die Übung es nur zum Beschriften von Dateien identifizieren soll, haben Sie viele Antworten. Wenn du das Archiv entpacken willst, warum versuchst du nicht einfach die Ausnahmen/Fehler zu finden? Zum Beispiel:

Verwandte Themen