28

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

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

何が必要です
か? ファイルの種類 (圧縮タイプ) を特定し、それらを非圧縮にするにはどうすればよいですか?


お気に入り:

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

etc  

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

4

7 に答える 7

37

このページには、「魔法の」ファイル署名のリストがあります。必要なものをつかみ、以下のような 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"

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

于 2012-10-24T07:53:38.823 に答える
17

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()」などの同様のメソッドを提供します。

于 2012-10-24T08:57:42.947 に答える
4

これは多くの要因に依存する複雑な問題です。最も重要なのは、ソリューションの移植性がどれだけ必要かということです。

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

例えば:

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、多くの作業を行うコマンドもあります。組み込みツールを使用してファイルを解凍することもできます。単純なスクリプトを実行するだけの場合は、この方法の方が単純で、パフォーマンスが向上します。

于 2012-10-24T07:32:36.970 に答える
0

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

>>> 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
于 2012-10-24T09:17:50.277 に答える
0

「a」は完全に誤りです。

「.zip」は、ファイルが実際に zip ファイルであることを意味するわけではないため、「b」は簡単に間違って解釈される可能性があります。拡張子が zip の JPEG である可能性があります (必要に応じて、紛らわしい目的で)。

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

于 2012-10-24T07:28:49.420 に答える