Chuyển đến nội dung chính

Làm việc với tệp Zip trong Python

Trong hướng dẫn này, bạn sẽ học cách làm việc với tệp Zip trong Python bằng mô-đun zipfile. zipfile là một mô-đun tích hợp sẵn của Python.
· 13 phút đọc

Khám phá cùng AI

Điều kiện tiên quyết để làm việc với tệp Zip

  • Bạn cần biết cách xử lý tệp trong Python để hiểu cách xử lý tệp Zip. Nếu bạn chưa biết về xử lý tệp, hãy xem mục File Handling trên W3Schools để học.
  • Khái niệm OOP trong Python
  • Các khái niệm Python như rẽ nhánh, vòng lặp, hàm, lớp, v.v.

Mở liên kết này để tải xuống tất cả các thư mục Zip mà tôi sẽ dùng ở các phần tiếp theo.

Tệp Zip là gì?

Zip là định dạng tệp lưu trữ hỗ trợ nén dữ liệu không mất mát. Tệp Zip là một tệp đơn chứa một hoặc nhiều tệp đã được nén.

Các cách sử dụng tệp Zip?

  • Tệp Zip giúp bạn gom các tệp liên quan vào cùng một nơi.
  • Tệp Zip giúp giảm kích thước dữ liệu.
  • Tệp Zip truyền tải nhanh hơn so với từng tệp riêng lẻ qua nhiều kết nối.

Mô-đun zipfile

Khám phá tất cả các phương thức và lớp của mô-đun zipfile bằng phương thức dir(). Xem đoạn mã để lấy tất cả lớp và phương thức của mô-đun zipfile.

import zipfile # importing the 'zipfile' module

print(dir(zipfile))
['BZIP2_VERSION', 'BadZipFile', 'BadZipfile', 'DEFAULT_VERSION', 'LZMACompressor', 'LZMADecompressor', 'LZMA_VERSION', 'LargeZipFile', 'MAX_EXTRACT_VERSION', 'PyZipFile', 'ZIP64_LIMIT', 'ZIP64_VERSION', 'ZIP_BZIP2', 'ZIP_DEFLATED', 'ZIP_FILECOUNT_LIMIT', 'ZIP_LZMA', 'ZIP_MAX_COMMENT', 'ZIP_STORED', 'ZipExtFile', 'ZipFile', 'ZipInfo', '_CD64_CREATE_VERSION', '_CD64_DIRECTORY_RECSIZE', '_CD64_DIRECTORY_SIZE', '_CD64_DISK_NUMBER', '_CD64_DISK_NUMBER_START', '_CD64_EXTRACT_VERSION', '_CD64_NUMBER_ENTRIES_THIS_DISK', '_CD64_NUMBER_ENTRIES_TOTAL', '_CD64_OFFSET_START_CENTDIR', '_CD64_SIGNATURE', '_CD_COMMENT_LENGTH', '_CD_COMPRESSED_SIZE', '_CD_COMPRESS_TYPE', '_CD_CRC', '_CD_CREATE_SYSTEM', '_CD_CREATE_VERSION', '_CD_DATE', '_CD_DISK_NUMBER_START', '_CD_EXTERNAL_FILE_ATTRIBUTES', '_CD_EXTRACT_SYSTEM', '_CD_EXTRACT_VERSION', '_CD_EXTRA_FIELD_LENGTH', '_CD_FILENAME_LENGTH', '_CD_FLAG_BITS', '_CD_INTERNAL_FILE_ATTRIBUTES', '_CD_LOCAL_HEADER_OFFSET', '_CD_SIGNATURE', '_CD_TIME', '_CD_UNCOMPRESSED_SIZE', '_ECD_COMMENT', '_ECD_COMMENT_SIZE', '_ECD_DISK_NUMBER', '_ECD_DISK_START', '_ECD_ENTRIES_THIS_DISK', '_ECD_ENTRIES_TOTAL', '_ECD_LOCATION', '_ECD_OFFSET', '_ECD_SIGNATURE', '_ECD_SIZE', '_EndRecData', '_EndRecData64', '_FH_COMPRESSED_SIZE', '_FH_COMPRESSION_METHOD', '_FH_CRC', '_FH_EXTRACT_SYSTEM', '_FH_EXTRACT_VERSION', '_FH_EXTRA_FIELD_LENGTH', '_FH_FILENAME_LENGTH', '_FH_GENERAL_PURPOSE_FLAG_BITS', '_FH_LAST_MOD_DATE', '_FH_LAST_MOD_TIME', '_FH_SIGNATURE', '_FH_UNCOMPRESSED_SIZE', '_SharedFile', '_Tellable', '_ZipDecrypter', '_ZipWriteFile', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '_check_compression', '_check_zipfile', '_get_compressor', '_get_decompressor', 'binascii', 'bz2', 'compressor_names', 'crc32', 'error', 'importlib', 'io', 'is_zipfile', 'lzma', 'main', 'os', 're', 'shutil', 'sizeCentralDir', 'sizeEndCentDir', 'sizeEndCentDir64', 'sizeEndCentDir64Locator', 'sizeFileHeader', 'stat', 'stringCentralDir', 'stringEndArchive', 'stringEndArchive64', 'stringEndArchive64Locator', 'stringFileHeader', 'struct', 'structCentralDir', 'structEndArchive', 'structEndArchive64', 'structEndArchive64Locator', 'structFileHeader', 'sys', 'threading', 'time', 'zlib']

Bạn thấy rất nhiều lớp và phương thức, đúng không? Nhưng bạn không cần học hết tất cả. Bạn sẽ chỉ học một số lớp và phương thức để làm việc với tệp Zip.

Hãy xem một vài Exception, Lớp và Phương thức hữu ích kèm giải thích ngắn.

Exceptions

Exception là thông báo dùng để hiển thị lỗi chính xác theo ý bạn. Trong Python, bạn dùng các từ khóa try, except, finally để xử lý lỗi.

Nếu bạn chưa quen với xử lý lỗi, hãy xem tài liệu Error Handling của Python để học.

Hãy xem các exception trong mô-đun zipfile.

zipfile.BadZipFile

zipfile.BadZipFile là một exception trong mô-đun zipfile. Lỗi này xảy ra với các tệp Zip lỗi. Xem ví dụ bên dưới.

## zipfile.BadZipFile
import zipfile

def main():
    try:
        with zipfile.ZipFile('sample_file.zip') as file: # opening the zip file using 'zipfile.ZipFile' class
            print("Ok")
    except zipfile.BadZipFile: # if the zip file has any errors then it prints the error message which you wrote under the 'except' block
        print('Error: Zip file is corrupted')

if __name__ == '__main__': main()

## I used a badfile for the test
Ok

zipfile.LargeZipFile

Giả sử bạn muốn làm việc với một tệp Zip lớn, bạn cần bật chức năng ZIP64 khi mở Zip. Nếu không bật, sẽ phát sinh LargeZipFile. Xem ví dụ.

## zipfile.LargeZipFile
## Without enabling 'Zip64'
import zipfile

def main():
    try:
        with zipfile.ZipFile('sample_file.zip') as file:
            print('File size is compatible')
    except zipfile.LargeZipFile: # it raises an 'LargeZipFile' error because you didn't enable the 'Zip64'
        print('Error: File size if too large')

if __name__ == '__main__': main()
File size is compatible
## zipfile.LargeZipFile
## With enabling 'ZIP64'
import zipfile

def main():
    try:
        with zipfile.ZipFile('sample_file.zip', mode = 'r', allowZip64 = True) as file: # here enabling the 'Zip64'
            print('File size is compatible')
    except zipfile.LargeZipFile:
        print('Error: File size if too large') # if the file size is too large to open it prints the error you have written

if __name__ == '__main__': main()
File size is compatible

Hãy chọn một tệp Zip phù hợp để xử lý Exception rồi chạy chương trình. Bạn sẽ nắm rõ hơn.

Classes

Nói đơn giản, class là tập hợp các phương thức và thuộc tính. Bạn dùng các phương thức và thuộc tính của class ở bất kỳ đâu bằng cách tạo instance của class.

Hãy xem một số lớp của mô-đun zipfile.

zipfile.ZipFile

Class phổ biến nhất để làm việc với tệp Zip là ZipFile.

zipfile.ZipFile dùng để ghi và đọc tệp Zip. Nó có một số phương thức để xử lý tệp Zip.

Bây giờ, hãy khám phá các phương thức của lớp ZipFile bằng đối tượng dir(). Xem mã.

import zipfile

print(dir(zipfile.ZipFile)) # accessing the 'ZipFile' class
['_RealGetContents', '__class__', '__del__', '__delattr__', '__dict__', '__dir__', '__doc__', '__enter__', '__eq__', '__exit__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_extract_member', '_fpclose', '_open_to_write', '_sanitize_windows_name', '_windows_illegal_name_trans_table', '_write_end_record', '_writecheck', 'close', 'comment', 'extract', 'extractall', 'fp', 'getinfo', 'infolist', 'namelist', 'open', 'printdir', 'read', 'setpassword', 'testzip', 'write', 'writestr']

Bạn đã dùng lớp zipfile.ZipFile để đọc tệp Zip ở các ví dụ trước.

zipfile.ZipFile có nhiều phương thức như extract, open, getinfo, setpassword, v.v. để làm việc với tệp Zip.

Hãy xem một vài phương thức của lớp ZipFile.

## zipfile.ZipFile
import zipfile

def main():
    with zipfile.ZipFile('sample_file.zip') as file:

        # ZipFile.infolist() returns a list containing all the members of an archive file
        print(file.infolist())

        # ZipFile.namelist() returns a list containing all the members with names of an archive file
        print(file.namelist())

        # ZipFile.getinfo(path = filepath) returns the information about a member of Zip file.
        # It raises a KeyError if it doesn't contain the mentioned file
        print(file.getinfo(file.namelist()[-1]))

        # ZipFile.open(path = filepath, mode = mode_type, pwd = password) opens the members of an archive file
        # 'pwd' is optional -> if it has password mention otherwise leave it
        text_file = file.open(name = file.namelist()[-1], mode = 'r')

        # 'read()' method of the file prints all the content of the file. You see this method in file handling.
        print(text_file.read())  

        # You must close the file if you don't open a file using 'with' keyword
        # 'close()' method is used to close the file
        text_file.close()

        # ZipFile.extractall(path = filepath, pwd = password) extracts all the files to current directory
        file.extractall()
        # after executing check the directory to see extracted files


if __name__ == '__main__': main()
[<ZipInfo filename='extra_file.txt' filemode='-rw-rw-rw-' file_size=59>, <ZipInfo filename='READ ME.txt' filemode='-rw-rw-rw-' file_size=59>, <ZipInfo filename='even_odd.py' filemode='-rw-rw-rw-' file_size=129>]
['extra_file.txt', 'READ ME.txt', 'even_odd.py']
<ZipInfo filename='even_odd.py' filemode='-rw-rw-rw-' file_size=129>
b"num = int(input('Enter a Number:- '))\r\nif num % 2 == 0:\r\n\tprint('{} is Even'.fromat(num))\r\nelse:\r\n\tprint('{} is Odd'.fromat(num))"

Nếu bạn muốn học tất cả các phương thức của lớp ZipFile, hãy dùng hàm help() trên phương thức bạn muốn tìm hiểu.

Hoặc truy cập tài liệu chính thức của Python để học.

zipfile.ZipInfo

Lớp zipfile.ZipInfo dùng để biểu diễn một thành viên trong thư mục Zip.

Trước hết, hãy khám phá tất cả đối tượng của lớp zipfile.ZipInfo bằng phương thức dir(). Xem mã dưới đây.

## zipfile.ZipInfo
import zipfile

print(dir(zipfile.ZipInfo))
['CRC', 'FileHeader', '__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', '_decodeExtra', '_encodeFilenameFlags', '_raw_time', 'comment', 'compress_size', 'compress_type', 'create_system', 'create_version', 'date_time', 'external_attr', 'extra', 'extract_version', 'file_size', 'filename', 'flag_bits', 'from_file', 'header_offset', 'internal_attr', 'is_dir', 'orig_filename', 'reserved', 'volume']

Bây giờ, bạn sẽ xem một vài phương thức của lớp zipfile.ZipInfo

## zipfile.ZipInfo
import zipfile

def main():
    with zipfile.ZipFile('sample_file.zip') as file:

        # 'infolist()' is the object of 'ZipFile' class
        # 'infolist()' returns a list containing all the folders and files of the zip -> 'ZipInfo' objects
        # assigning last element of the list to a variable to test all the methods of 'ZipInfo'
        archive = file.infolist()
        read_me_file = archive[-1]

        # 'ZipInfo' methods

        # ZipInfo_object.filename returns the name of the file
        print("Name of the file:- {}".format(read_me_file.filename))

        # ZipInfo_object.file_size returns the size of the file
        print("Size of the file:- {}".format(read_me_file.file_size))

        # ZipInfo_object.is_dir() returns True if it's directory otherwise False
        print("Is directory:- {}".format(read_me_file.is_dir()))

        # ZipInfo_object.date_time() returns the created date & time of file
        print("File created data & time:- {}".format(read_me_file.date_time))

if __name__ == '__main__': main()
Name of the file:- sample_file/READ ME.txt
Size of the file:- 59
Is directory:- False
File created data & time:- (2018, 10, 4, 11, 32, 22)

Vào ZipInfo nếu bạn muốn tìm hiểu thêm về các đối tượng của ZipInfo.

Methods

Methods là một khối mã cho một chức năng cụ thể trong chương trình. Ví dụ, nếu bạn muốn tìm giá trị tuyệt đối của một số, bạn có thể dùng phương thức abs của Python.

Bạn có thể dùng ở bất kỳ đâu. Hãy xem một vài phương thức của mô-đun zipfile.

zipfile.is_zipfile()

Phương thức is_zipfile(filename) của mô-đun zipfile trả về True nếu tệp là Zip hợp lệ, ngược lại trả về False.

Hãy xem ví dụ.

## zipfile.is_zip(filename)
import zipfile

def main():
    print(zipfile.is_zipfile('sample_file.zip')) # it returns True

if __name__ == '__main__': main()
True

Xử lý tệp Zip

Trong phần này, bạn sẽ học cách xử lý tệp Zip như Mở, Giải nén, Ghi, v.v.

Giải nén một tệp Zip

Giải nén các tệp trong một tệp Zip bằng phương thức extractall vào thư mục hiện tại.

## extracting zip file
import zipfile

def main():

    # assigning filename to a variable
    file_name = 'sample_file.zip'

    # opening Zip using 'with' keyword in read mode
    with zipfile.ZipFile(file_name, 'r') as file:
        # printing all the information of archive file contents using 'printdir' method
        print(file.printdir())

        # extracting the files using 'extracall' method
        print('Extracting all files...')
        file.extractall()
        print('Done!') # check your directory of zip file to see the extracted files

if __name__ == '__main__': main()
File Name                                             Modified             Size
sample_file/                                   2018-10-04 11:33:22            0
sample_file/even_odd.py                        2018-06-29 23:35:54          129
sample_file/READ ME.txt                        2018-10-04 11:32:22           59
None
Extracting all files...
Done!

Giải nén tệp Zip có mật khẩu

Để giải nén một tệp Zip có mật khẩu, bạn cần truyền giá trị cho đối số pwd của các phương thức extract(pwd = password) hoặc extractall(pwd = password).

Bạn phải truyền mật khẩu ở dạng bytes. Để chuyển str sang bytes, dùng phương thức tích hợp bytes của Python với mã hóa utf-8.

Hãy xem ví dụ.

## extracting zip with password
import zipfile

def main():
    file_name = 'pswd_file.zip'
    pswd = 'datacamp'

    with zipfile.ZipFile(file_name) as file:
        # password you pass must be in the bytes you converted 'str' into 'bytes'
        file.extractall(pwd = bytes(pswd, 'utf-8'))

if __name__ == '__main__': main()

Bạn cũng có thể giải nén bằng cách dùng phương thức setpassword(pwd = password) của lớp ZipFile. Xem ví dụ dưới đây.

## extracting zip with password
import zipfile

def main():
    file_name = 'pswd_file.zip'
    pswd = 'datacamp'

    with zipfile.ZipFile(file_name) as file:
        # 'setpassword' method is used to give a password to the 'Zip'
        file.setpassword(pwd = bytes(pswd, 'utf-8'))
        file.extractall()

if __name__ == '__main__': main()

Tạo tệp Zip

Để tạo một tệp Zip, bạn không cần phương thức bổ sung nào. Chỉ cần truyền tên cho lớp ZipFile, nó sẽ tạo một kho lưu trữ trong thư mục hiện tại.

Xem ví dụ dưới đây.

## Creating Zip file
import zipfile

def main():

    archive_name = 'example_file.zip'
    # below one line of code will create a 'Zip' in the current working directory
    with zipfile.ZipFile(archive_name, 'w') as file:
        print("{} is created.".format(archive_name))

if __name__ == '__main__': main()
example_file.zip is created.

Ghi vào tệp Zip

Bạn phải mở tệp Zip ở chế độ ghi để ghi tệp vào kho lưu trữ. Nó sẽ ghi đè tất cả tệp hiện có trong Zip.

Hãy xem ví dụ.

## Writing files to zip
import zipfile

def main():

    file_name = 'sample_file.zip'

    # Opening the 'Zip' in writing mode
    with zipfile.ZipFile(file_name, 'w') as file:
        # write mode overrides all the existing files in the 'Zip.'
        # you have to create the file which you have to write to the 'Zip.'
        file.write('extra_file.txt')
        print('File overrides the existing files')

    # opening the 'Zip' in reading mode to check
    with zipfile.ZipFile(file_name, 'r') as file:
        print(file.namelist())

if __name__ == '__main__': main()
File overrides the existing files
['extra_file.txt']

Thêm tệp vào Zip

Bạn phải mở Zip ở chế độ append(a) để thêm tệp vào Zip. Nó không ghi đè các tệp hiện có.

Hãy xem ví dụ.

## Appending files to zip
import zipfile

def main():

    file_name = 'sample_file.zip'

    # opening the 'Zip' in writing mode
    with zipfile.ZipFile(file_name, 'a') as file:
        # append mode adds files to the 'Zip'
        # you have to create the files which you have to add to the 'Zip'
        file.write('READ ME.txt')
        file.write('even_odd.py')
        print('Files added to the Zip')

    # opening the 'Zip' in reading mode to check
    with zipfile.ZipFile(file_name, 'r') as file:
        print(file.namelist())

if __name__ == '__main__': main()
Files added to the Zip
['extra_file.txt', 'READ ME.txt', 'even_odd.py']

Đến đây, bạn đã học cách xử lý tệp Zip. Giờ bạn có thể mở, ghi, thêm, giải nén, tạo, v.v. tệp Zip. Tiếp theo, bạn sẽ viết một chương trình đơn giản.

Đó là gì?

Giải nén nhiều tệp Zip lồng nhau có mật khẩu bằng vòng lặp và zipfile

  • Bạn có một tệp Zip chứa một số tệp Zip con ở nhiều cấp. Mỗi tệp Zip có mật khẩu là chính tên của nó. Thử thách là giải nén tất cả các Zip cho đến khi bạn đến cuối.

Các bước giải quyết vấn đề

  • Giải nén tệp cha bằng chính tên của nó làm mật khẩu.
  • Lấy tên tệp con đầu tiên bằng phương thức namelist(). Lưu vào một biến.
  • Chạy vòng lặp vô hạn.

    • Kiểm tra xem tệp có phải Zip hay không bằng phương thức is_zipfile(). Nếu có, thực hiện các bước sau.

      • Mở zip với biến name.

      • Lấy mật khẩu của Zip từ biến name.

      • Giải nén Zip.

      • Lấy và lưu tên Zip tiếp theo vào biến name.

    • ngược lại

      • Dừng vòng lặp bằng break.

Tôi đã tạo quy trình trên. Nếu muốn, bạn có thể thay đổi cho phù hợp với cách sắp xếp tệp của bạn.

## Solution
import zipfile

def main():

    # storing the parent name
    parent_file_name = '000.zip'

    with zipfile.ZipFile(parent_file_name, 'r') as parent_file:

        # extracting the parent file
        pswd = bytes(parent_file_name.split('.')[0], 'utf-8')
        parent_file.extractall(pwd = pswd)

        # getting the first child
        next_zip_name = parent_file.namelist()[0]

        # looping through the sub zips infinite times until you don't encouter a 'Zip' file
        while True:

            if zipfile.is_zipfile(next_zip_name):
                # opening the zip
                with zipfile.ZipFile(next_zip_name, 'r') as child_file:

                    # getting password from the zip name
                    pswd = bytes(next_zip_name.split('.')[0], 'utf-8')

                    # extracting the zip
                    child_file.extractall(pwd = pswd)

                    # getting the child zip name
                    next_zip_name = child_file.namelist()[0]
            else:
                break

if __name__ == '__main__': main()

Sau khi chạy chương trình trên, bạn sẽ thấy tất cả các tệp zip con được giải nén vào thư mục hiện tại.

Lời kết

Chúc mừng bạn đã hoàn thành hướng dẫn!

Hy vọng bạn thích bài hướng dẫn. Bài viết này sẽ rất hữu ích khi bạn làm việc với các tệp Zip. Giờ đây, bạn có thể làm việc với các tệp Zip.

Nếu bạn có thắc mắc nào về bài viết, hãy hỏi tôi trong phần bình luận. Tôi sẽ trả lời sớm nhất có thể.

Một lần nữa, nếu bạn mới bắt đầu với Python, hãy học khóa miễn phí Intro to Python for Data Science của DataCamp để học ngôn ngữ Python hoặc đọc tài liệu chính thức của Python.

Chúc bạn viết code vui vẻ!

Chủ đề

Liên quan