2012-10-24 29 views
18

Một tệp nén có thể được phân loại thành các nhóm hợp lý dưới đây
a. Hệ điều hành bạn đang làm việc (* ix, Win), v.v.
b. Các loại thuật toán nén khác nhau (ví dụ: .zip, .Z, .bz2, .rar, .gzip). Atleast từ một danh sách tiêu chuẩn của các tệp nén được sử dụng chủ yếu.
c. Sau đó, chúng tôi có cơ chế bóng tar - nơi tôi cho rằng không có nén. Nhưng nó hoạt động giống như một nối.Python - cơ chế để xác định loại tệp nén và giải nén

Bây giờ, nếu chúng tôi bắt đầu giải quyết tập hợp các tệp nén ở trên,
a. Tùy chọn (a) sẽ được chăm sóc bởi python vì nó là ngôn ngữ độc lập nền tảng.
b. Tùy chọn (b) và (c) dường như có vấn đề.

Tôi cần gì
Làm cách nào để xác định loại tệp (loại nén) và sau đó nén UN?


Giống như:

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

etc 

Vậy câu hỏi cơ bản là làm thế nào để chúng tôi xác định các thuật toán nén dựa trên tập tin (giả sử phần mở rộng không được cung cấp hoặc không chính xác)? Có cách nào cụ thể để làm điều đó trong python?

Trả lời

26

This page có danh sách chữ ký tệp "ma thuật". Lấy những cái bạn cần và đặt chúng trong một dict như dưới đây. Sau đó, chúng tôi cần một chức năng phù hợp với các phím dict với sự khởi đầu của tập tin.Tôi đã viết một đề xuất, mặc dù nó có thể được tối ưu hóa bằng cách xử lý trước magic_dict vào ví dụ: một regexp biên dịch khổng lồ.

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" 

Giải pháp này nên được cross-plattform và tất nhiên là không phụ thuộc vào phần mở rộng tên tập tin, nhưng nó có thể cung cấp cho dương tính giả cho các tập tin với nội dung ngẫu nhiên mà chỉ xảy ra để bắt đầu với một số byte ma thuật cụ thể.

+0

Điều này xác định rõ ràng loại tệp. Tuy nhiên, bạn nên quay trở lại đối tượng được tạo bằng cách mở tệp và cho phép truy cập. Nếu không, bạn sẽ kết thúc thử nghiệm loại tệp một lần nữa để xem bạn có cần xử lý hay không. Điều này có thể tránh được bằng cách tạo một trừu tượng chung có thể xử lý tất cả các loại tệp được hỗ trợ. Mẫu này gọi là "nhà máy". – Ber

+0

Bạn cũng có thể sử dụng trang này để tìm kiếm chữ ký bạn muốn: http://www.filesignatures.net/index.php –

+0

Định dạng tệp zip cho phép dữ liệu tùy ý được nối vào đầu tệp, vì vậy hãy kiểm tra số ma thuật cho các tệp zip không chính xác trong mọi trường hợp. –

0

"a" là hoàn toàn sai.

"b" có thể dễ dàng được diễn giải sai, vì ".zip" không có nghĩa là tệp thực sự là tệp zip. Nó có thể là một JPEG với phần mở rộng zip (cho mục đích khó hiểu, nếu bạn muốn).

Bạn thực sự cần phải kiểm tra xem dữ liệu bên trong tệp có khớp với dữ liệu dự kiến ​​có bởi phần mở rộng của nó hay không. Ngoài ra, hãy xem magic byte.

+0

Với tùy chọn (a), tôi chỉ có nghĩa là mã được viết bằng python để hủy nén nói Unix, phải làm việc cho cùng một tệp không nén trong WIN. Bất kỳ lý do cụ thể mà tôi sai? –

+1

Thuật toán nén là hệ điều hành độc lập. Bạn có thể nén một tập tin trong Unix, sau đó giải nén nó trên WIndows, sau đó gửi nó vào máy Mac và nén nó một lần nữa, so sánh các tập tin nén từ Unix và một từ Mac và họ sẽ được bit-a-bit bằng nhau. – alexandernst

+0

@kumar_m_kiran Nói chung (rất có thể) bạn có thể sử dụng cùng một mã python để giải nén tập tin trên hệ điều hành bằng cách sử dụng python. Bạn có nghĩa là phân loại dựa trên mã python cần thiết để giải nén trên các hệ điều hành khác nhau (là nền tảng độc lập mang lại) với sự hiểu biết (không chính xác) rằng các hệ điều hành khác nhau sẽ cần mã python khác nhau (nói chung là không đúng). Nhưng bạn nói như vậy với một sự lựa chọn của các từ đó có nghĩa là cái gì khác và alexandernst sửa chữa bạn. – abc

3

Đây là một câu hỏi phức tạp phụ thuộc vào một số yếu tố: quan trọng nhất là giải pháp di động của bạn cần phải như thế nào.

Những điều cơ bản đằng sau việc tìm loại tệp được cung cấp cho tệp là tìm tiêu đề xác định trong tệp, thường được gọi là "magic sequence" or signature header, xác định rằng tệp thuộc một loại nhất định. Tên hoặc phần mở rộng của nó thường không được sử dụng nếu nó có thể tránh được. Đối với một số tệp, Python đã tích hợp sẵn. Ví dụ: để xử lý các tệp .tar, bạn có thể sử dụng mô-đun tarfile, có phương thức is_tarfile thuận tiện. Có một mô-đun tương tự có tên là zipfile. Các mô-đun này cũng sẽ cho phép bạn trích xuất các tệp bằng Python thuần túy.

Ví dụ:

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

Nếu giải pháp của bạn là Linux hoặc OSX chỉ, đó cũng là file lệnh đó sẽ làm được rất nhiều việc cho bạn. Bạn cũng có thể sử dụng các công cụ tích hợp để giải nén các tệp. Nếu bạn chỉ làm một kịch bản đơn giản, phương pháp này đơn giản hơn và sẽ cho bạn hiệu suất tốt hơn.

13

Dựa trên câu trả lời lazyr và nhận xét của tôi, đây là những gì tôi muốn nói:

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 

Bây giờ có thể truy cập dữ liệu nén sử dụng cf.accessor. Tất cả các mô-đun cung cấp các phương thức tương tự như 'read()', 'write()', v.v. để thực hiện điều này.

+0

trong hàm get_compressed_file bạn đang làm cls (f), f là một trình xử lý tệp, trong khi các hàm mở của bạn đang chờ tên tệp ... Tôi đã sửa đổi nó để đóng f và chuyển tên tệp thay thế. Có cách nào tốt hơn? – fransua

+0

nhận xét trước đó của tôi có thể liên quan đến phiên bản python ... trong python2 bz2.BZ2File chỉ chấp nhận chuỗi – fransua

0

Nếu bài tập là để xác định nó chỉ để ghi nhãn, bạn có rất nhiều câu trả lời. Nếu bạn muốn giải nén kho lưu trữ, tại sao bạn không thử và nắm bắt các lỗi/lỗi? Ví dụ:

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