web-dev-qa-db-ja.com

Python-圧縮ファイルタイプを識別して解凍するメカニズム

圧縮ファイルは、以下の論理グループに分類できます
a。使用しているオペレーティングシステム(* ix、Win)など.
b。さまざまな種類の圧縮アルゴリズム(つまり、.Zip、.Z、.bz2、.rar、.gzip)。主に使用される圧縮ファイルの標準リストから少なくとも。
c。次に、タールボールメカニズムを使用します。圧縮は行われないと思います。しかし、それは連結のように機能します。

ここで、上記の一連の圧縮ファイルのアドレス指定を開始すると、
a。オプション(a)は、プラットフォームに依存しない言語であるため、pythonによって処理されます。
b。オプション(b)および(c)に問題があるようです。

必要なもの
ファイルの種類(圧縮の種類)を識別して、それらをUN圧縮するにはどうすればよいですか?


お気に入り:

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

etc  

したがって、基本的な質問は、ファイルに基づいて圧縮アルゴリズムをどのように特定するかです(拡張子が提供されていない、または正しくないと想定)。 Pythonでそれを行う特定の方法はありますか?

27
kumar_m_kiran

このページ には、「マジック」ファイル署名のリストがあります。必要なものを手に取り、以下のような辞書に入れてください。次に、dictキーをファイルの先頭に一致させる関数が必要です。提案は書きましたが、magic_dictを前処理して最適化することもできます。 1つの巨大なコンパイル済み正規表現。

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"

このソリューションはクロスプラットフォームである必要があり、ファイル名の拡張子に依存しませんが、特定のマジックバイトで始まるランダムなコンテンツを持つファイルに対して誤検知が発生する可能性があります。

31

Lazyrの答えと私のコメントに基づいて、ここに私が意味するものがあります:

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

cf.accessorを使用して圧縮データにアクセスできるようになりました。これを行うために、すべてのモジュールが「read()」、「write()」などのような同様のメソッドを提供します。

14
Ber

これは、いくつかの要因に依存する複雑な質問です。最も重要なのは、ソリューションの移植性の必要性です。

ファイルを指定してファイルの種類を見つけることの背後にある基本は、ファイル内の識別ヘッダーを見つけることです。これは通常、ファイルが特定のタイプであることを識別する "マジックシーケンス"または署名ヘッダー と呼ばれるものです。回避できる場合、その名前または拡張子は通常使用されません。一部のファイルでは、Pythonにこれが組み込まれています。たとえば、_.tar_ファイルを処理するには、tarfileモジュールを使用できます。これは、便利な_is_tarfile_メソッド。zipfileという名前の同様のモジュールがあります。これらのモジュールを使用すると、純粋なPythonでファイルを抽出することもできます。

例えば:

_f = file('myfile','r')
if zipfile.is_zipfile(f):
    Zip = zipfile.ZipFile(f)
    Zip.extractall('/dest/dir')
Elif tarfile.is_tarfile(f):
    ...
_

ソリューションがLinuxまたはOSXのみの場合は、fileコマンドもあり、多くの作業が行われます。組み込みツールを使用してファイルを解凍することもできます。単純なスクリプトを実行しているだけの場合、この方法はより単純で、パフォーマンスが向上します。

4
Krumelur

「a」は完全に偽です。

「.Zip」はファイルが実際にZipファイルであることを意味しないため、「b」は簡単に誤って解釈される可能性があります。必要に応じて、Zip拡張子付きのJPEGにすることもできます(混乱を招くため)。

実際には、ファイル内のデータが、拡張子によって予想されるデータと一致するかどうかを確認する必要があります。 マジックバイト も見てください。

0
alexandernst

演習がファイルをラベル付けするためだけにそれを識別することである場合、あなたは多くの答えを持っています。アーカイブを解凍したい場合は、実行/エラーをキャッチしてみませんか?例えば:

>>> tarfile.is_tarfile('lala.txt')
False
>>> zipfile.is_zipfile('lala.txt')
False
>>> with bz2.BZ2File('startup.bat','r') as f:
...    f.read()
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
IOError: invalid data stream
0
Burhan Khalid

2019アップデート:
。csvファイルがgzip圧縮されているかどうかを検出するソリューションを探していました。 @Lauritzの答えは私にエラーを投げていました。これは、過去7年間にファイルの読み取り方法が変更されたからだと思います。

このライブラリは私にとって完璧に機能しました! https://pypi.org/project/filetype/

0
Red