ficheiro zip para comprimir e descomprimir ficheiros ZIP em Python

O negócio

O módulo zipfile da biblioteca padrão Python pode ser utilizado para comprimir ficheiros em ZIPs e descomprimir ficheiros ZIP. Está incluído na biblioteca padrão, pelo que não é necessária qualquer instalação adicional.

Os seguintes conteúdos são explicados.

  • Comprimir vários ficheiros num ficheiro ZIP
  • Acrescentar um novo ficheiro a um ficheiro ZIP existente
  • Comprimir um directório (pasta) para um ficheiro ZIP
  • Comprimido para um ficheiro ZIP com uma palavra-passe
  • Verifique o conteúdo do ficheiro ZIP.
  • Extrair (desembalar) todo o conteúdo do ficheiro ZIP.
  • Seleccione o conteúdo do ficheiro ZIP e extraia-o.

Comprimir vários ficheiros num ficheiro ZIP

Criar um objecto ZipFile e utilizar o método write() para adicionar os ficheiros que deseja comprimir.

Para criar um novo ficheiro ZIP, especificar o caminho do ficheiro ZIP a ser criado como primeiro argumento do construtor do objecto ZipFile, e o segundo argumento como se segue'w'

Além disso, o método de compressão pode ser especificado como o terceiro argumento.

  • zipfile.ZIP_STORED:Basta combinar vários ficheiros sem compressão (por defeito)
  • zipfile.ZIP_DEFLATED:Compressão ZIP normal (é necessário módulo zlib)
  • zipfile.ZIP_BZIP2:Compressão BZIP2 (é necessário o módulo bz2)
  • zipfile.ZIP_LZMA:Compressão LZMA (é necessário módulo lzma)

BZIP2 e LZMA têm uma maior taxa de compressão (pode ser comprimido para um tamanho menor), mas o tempo necessário para a compressão é maior.

No método write(), o ficheiro com o primeiro argumento nome de ficheiro é escrito num ficheiro ZIP com o segundo argumento nome de arco. Se arcname for omitido, o nome do ficheiro é utilizado como está. arcname pode também especificar uma estrutura de directório.

O objecto ZipFile precisa de ser fechado com o método close(), mas se utilizar o com declaração, este será fechado automaticamente quando o bloco estiver terminado.

import zipfile

with zipfile.ZipFile('data/temp/new_comp.zip', 'w', compression=zipfile.ZIP_DEFLATED) as new_zip:
    new_zip.write('data/temp/test1.txt', arcname='test1.txt')
    new_zip.write('data/temp/test2.txt', arcname='zipdir/test2.txt')
    new_zip.write('data/temp/test3.txt', arcname='zipdir/sub_dir/test3.txt')

Ao especificar o argumento do tipo de compressão do método write(), é também possível seleccionar o método de compressão para cada ficheiro.

with zipfile.ZipFile('data/temp/new_comp_single.zip', 'w') as new_zip:
    new_zip.write('data/temp/test1.txt', arcname='test1.txt', compress_type=zipfile.ZIP_DEFLATED)
    new_zip.write('data/temp/test2.txt', arcname='zipdir/test2.txt')
    new_zip.write('data/temp/test3.txt', arcname='zipdir/sub_dir/test3.txt')

Acrescentar um novo ficheiro a um ficheiro ZIP existente

Para adicionar um novo ficheiro a um ficheiro zip existente, defina o primeiro argumento do construtor para o caminho do ficheiro zip existente ao criar o objecto ZipFile. Além disso, defina o segundo argumento como se segue.'a'

Depois, como no exemplo acima, basta adicionar o ficheiro usando o método write().

with zipfile.ZipFile('data/temp/new_comp.zip', 'a') as existing_zip:
    existing_zip.write('data/temp/test4.txt', arcname='test4.txt')

Comprimir um directório (pasta) para um ficheiro ZIP

Se quiser comprimir todo um directório (pasta) num único ficheiro ZIP, pode usar os.scandir() ou os.listdir() para fazer uma lista de ficheiros, mas é mais fácil usar make_archive() no módulo shutil.

Ver o artigo seguinte.

Comprimido para um ficheiro ZIP com uma palavra-passe

O módulo zipfile não lhe permite criar ZIPs protegidos por palavra-passe. Se quiser comprimir um ficheiro num ficheiro zip protegido por palavra-passe, utilize a biblioteca de terceiros pyminizip.

Note que a descompressão de ZIPs protegidos por palavra-passe pode ser feita com o módulo de ficheiro zip (ver abaixo).

Verifique o conteúdo do ficheiro ZIP.

Pode verificar o conteúdo de um ficheiro ZIP existente.

Criar um objecto ZipFile definindo o primeiro ficheiro de argumento no construtor para o caminho do ficheiro zip existente e o segundo modo de argumento para 'r'. O argumento do modo pode ser omitido uma vez que o padrão é 'r'.

Pode usar o método namelist() do objecto ZipFile para obter uma lista de ficheiros arquivados.

with zipfile.ZipFile('data/temp/new_comp.zip') as existing_zip:
    print(existing_zip.namelist())
# ['test1.txt', 'zipdir/test2.txt', 'zipdir/sub_dir/test3.txt', 'test4.txt']

Extrair (desembalar) todo o conteúdo do ficheiro ZIP.

Para desembalar o conteúdo de um ficheiro ZIP, criar um objecto ZipFile com o primeiro ficheiro de argumento no construtor como o caminho para o ficheiro ZIP existente e o segundo modo de argumento como 'r', como no exemplo acima. O argumento do modo pode ser omitido, uma vez que o seu valor por defeito é 'r'.

O método extractall() do objecto ZipFile extrai (descomprime) a totalidade do conteúdo do ficheiro ZIP. O primeiro argumento, caminho, especifica o caminho do directório a extrair. Se for omitido, os ficheiros serão extraídos para o directório actual.

with zipfile.ZipFile('data/temp/new_comp.zip') as existing_zip:
    existing_zip.extractall('data/temp/ext')

Um ficheiro ZIP com uma palavra-passe pode ser extraído especificando a palavra-passe como o argumento pwd do método extractall().

with zipfile.ZipFile('data/temp/new_comp_with_pass.zip') as pass_zip:
    pass_zip.extractall('data/temp/ext_pass', pwd='password')

Seleccione o conteúdo do ficheiro ZIP e extraia-o.

Se quiser desembalar e extrair apenas certos ficheiros, utilize o método extract().

O primeiro argumento do método extract() é o nome do ficheiro a extrair, e o segundo argumento caminho é o caminho do directório a extrair. Se o argumento do caminho for omitido, o ficheiro será extraído para o directório actual. O nome do ficheiro a extrair deve incluir o caminho para o directório no ficheiro ZIP, se este estiver aí armazenado.

with zipfile.ZipFile('data/temp/new_comp.zip') as existing_zip:
    existing_zip.extract('test1.txt', 'data/temp/ext2')

Tal como o método extractall(), o método extract() também lhe permite especificar uma palavra-passe como argumento pwd.

with zipfile.ZipFile('data/temp/new_comp_with_pass.zip') as pass_zip:
    pass_zip.extract('test1.txt', 'data/temp/ext_pass2', pwd='password')