Curso
Pré-requisitos para trabalhar com arquivos ZIP
- Você precisa conhecer a manipulação de arquivos em Python para entender como lidar com arquivos ZIP. Se ainda não conhece, veja a seção File Handling do W3Schools.
- Conceitos de OOP (programação orientada a objetos) em Python
- Conceitos de Python como condicionais, loops, funções, classes etc.
- Se você não sabe Python, faça o curso gratuito da DataCamp Intro to Python for Data Science para aprender a linguagem Python ou leia a documentação oficial do Python.
Abra este link para baixar todas as pastas ZIP que usei nas próximas seções.
O que é um arquivo ZIP?
ZIP é um formato de arquivo de arquivamento que oferece compactação de dados sem perdas. Um arquivo ZIP é um único arquivo que contém um ou mais arquivos compactados.
Para que servem os arquivos ZIP?
- Arquivos ZIP ajudam você a reunir arquivos relacionados em um só lugar.
- Arquivos ZIP ajudam a reduzir o tamanho dos dados.
- Arquivos ZIP são transferidos mais rápido do que arquivos individuais em muitas conexões.
Módulo zipfile
Explore todos os métodos e classes do módulo zipfile usando o método dir(). Veja o código para listar todas as classes e métodos do módulo 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']
Você viu um monte de classes e métodos, certo? Mas não vai aprender todos. Vamos focar nas classes e métodos necessários para trabalhar com arquivos ZIP.
Veja algumas exceções, classes e métodos úteis com explicações rápidas.
Exceções
Exceção é uma mensagem usada para exibir o erro exato do jeito que você quiser. Em Python, você usa as palavras-chave try, except, finally para tratar erros.
Se não estiver familiarizado com tratamento de erros, consulte a documentação de Error Handling do Python.
Vamos ver todas as exceções do módulo zipfile.
zipfile.BadZipFile
zipfile.BadZipFile é uma exceção do módulo zipfile. Esse erro é lançado para arquivos ZIP corrompidos. Veja o exemplo abaixo.
## 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
Se você for trabalhar com um arquivo ZIP grande, precisa habilitar o recurso ZIP64 ao abrir o ZIP. Se não habilitar, a exceção LargeZipFile será lançada. Veja o exemplo.
## 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
Escolha um arquivo ZIP adequado para testar o tratamento de exceções e execute o programa. Vai ficar bem claro.
Classes
Em poucas palavras, uma classe é um conjunto de métodos e atributos. Você usa os métodos e atributos da classe onde quiser criando instâncias dessa classe.
Vamos ver algumas classes do módulo zipfile.
zipfile.ZipFile
A classe mais comum para trabalhar com arquivos ZIP é a ZipFile.
zipfile.ZipFile é usada para escrever e ler arquivos ZIP. Ela tem métodos para manipular esses arquivos.
Agora, explore os métodos da classe ZipFile usando dir(). Veja o código.
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']
Você já usou a classe zipfile.ZipFile para ler arquivos ZIP nos exemplos anteriores.
zipfile.ZipFile inclui vários métodos como extract, open, getinfo, setpassword etc., para trabalhar com arquivos ZIP.
Vamos ver alguns métodos da classe 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))"
Se quiser aprender todos os métodos da classe ZipFile, use a função help() no método que deseja conhecer.
Ou vá à documentação oficial do Python.
zipfile.ZipInfo
A classe zipfile.ZipInfo representa um membro de uma pasta ZIP.
Primeiro, explore todos os objetos da classe zipfile.ZipInfo usando o método dir(). Veja o código abaixo.
## 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']
Agora, veja alguns métodos da classe 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á para a documentação do ZipInfo se quiser saber mais sobre os objetos de ZipInfo.
Métodos
Métodos são blocos de código com uma funcionalidade específica no programa. Por exemplo, se você quer o valor absoluto de um número, pode usar o método embutido do Python chamado abs.
Você pode usá-los onde quiser. Vamos ver alguns métodos do módulo zipfile.
zipfile.is_zipfile()
O método is_zipfile(filename) do módulo zipfile retorna True se o arquivo for um ZIP válido; caso contrário, retorna False.
Veja um exemplo.
## zipfile.is_zip(filename)
import zipfile
def main():
print(zipfile.is_zipfile('sample_file.zip')) # it returns True
if __name__ == '__main__': main()
True
Como manipular arquivos ZIP
Nesta seção, você vai aprender a manipular arquivos ZIP como abrir, extrair, escrever etc.
Extraindo um arquivo ZIP
Extraindo os arquivos de um ZIP para o diretório atual usando o método extractall.
## 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!
Extraindo um ZIP com senha
Para extrair um ZIP com senha, você precisa passar um valor para o argumento posicional pwd dos métodos extract(pwd = password) ou extractall(pwd = password).
Você deve passar a senha em bytes. Para converter uma str em bytes, use o método embutido bytes do Python com codificação utf-8.
Veja um exemplo.
## 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()
Você também pode extrair arquivos usando o método setpassword(pwd = password) da classe ZipFile. Veja o exemplo abaixo.
## 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()
Criando arquivos ZIP
Para criar um arquivo ZIP, você não precisa de nenhum método extra. Basta passar o nome para a classe ZipFile e ela criará o arquivo compactado no diretório atual.
Veja o exemplo abaixo.
## 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.
Escrevendo em arquivos ZIP
Você deve abrir arquivos ZIP em modo de escrita para gravar arquivos no pacote. Esse modo sobrescreve todos os arquivos existentes no ZIP.
Veja um exemplo.
## 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']
Acrescentando arquivos ao ZIP
Você deve abrir o ZIP em modo de acréscimo (a) para adicionar arquivos ao ZIP. Nesse modo, os arquivos existentes não são sobrescritos.
Veja um exemplo.
## 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']
Até aqui, você aprendeu a manipular arquivos ZIP. Agora você consegue abrir, escrever, acrescentar, extrair, criar etc. arquivos ZIP. Vamos escrever um programinha.
Qual é a ideia?
Extraindo vários sub-ZIPs com senha usando loops e zipfile
- Você tem um ZIP que contém alguns subarquivos ZIP em níveis. Cada um desses ZIPs tem como senha o próprio nome. O desafio é descompactar todos os ZIPs até chegar ao fim.
Passos para resolver o problema
- Extraia o arquivo pai usando o próprio nome como senha.
- Obtenha o nome do primeiro filho com o método namelist(). Guarde em uma variável.
-
Execute um loop por tempo indeterminado.
-
Verifique se o arquivo é ZIP com is_zipfile(). Se for, faça o seguinte:
-
Abra o ZIP usando a variável name.
-
Obtenha a senha do ZIP a partir da variável name.
-
Extraia o ZIP.
-
Obtenha e armazene o próximo nome de ZIP na variável name.
-
-
caso contrário
- Interrompa o loop com break.
-
Montei o procedimento acima. Se quiser, adapte conforme a organização dos seus arquivos.
## 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()
Depois de executar o programa acima, você verá que todos os sub-ZIPs foram extraídos para o diretório atual.
Considerações finais
Parabéns por concluir o tutorial!
Espero que tenha gostado. Este artigo ajuda bastante quando você está trabalhando com arquivos ZIP. Agora você já consegue lidar com arquivos ZIP.
Se tiver alguma dúvida sobre o artigo, deixe nos comentários. Eu respondo o quanto antes.
Se você é novo em Python, faça o curso gratuito da DataCamp Intro to Python for Data Science para aprender a linguagem Python ou leia a documentação oficial do Python.
Bons códigos!
