proyectos ejemplos python zipfile

python - ejemplos - Cómo crear un archivo zip de un directorio



django (19)

¿Cómo puedo crear un archivo zip de una estructura de directorios en Python?


¿Cómo puedo crear un archivo zip de una estructura de directorios en Python?

En un script de Python

En Python 2.7+, shutil tiene una función make_archive .

from shutil import make_archive make_archive( ''zipfile_name'', ''zip'', # the archive format - or tar, bztar, gztar root_dir=None, # root for archive - current working dir if None base_dir=None) # start archiving from here - cwd if None too

Aquí el archivo comprimido se llamará zipfile_name.zip . Si base_dir está más abajo de root_dir , excluirá los archivos que no base_dir en base_dir , pero aún así archivará los archivos en los root_dir padre hasta root_dir .

Tuve un problema al probar esto en Cygwin con 2.7 - quiere un argumento root_dir, para cwd:

make_archive(''zipfile_name'', ''zip'', root_dir=''.'')

Usando Python desde la shell

Puedes hacer esto con Python desde el shell también usando el módulo zipfile :

$ python -m zipfile -c zipname sourcedir

Donde zipname es el nombre del archivo de destino que desea (agregue .zip si lo desea, no lo hará automáticamente) y sourcedir es la ruta al directorio.

Cremalleando Python (o simplemente no quiero el directorio principal):

Si estás tratando de comprimir un paquete de python con un __init__.py y __main__.py , y no quieres el directorio padre, es

$ python -m zipfile -c zipname sourcedir/*

Y

$ python zipname

ejecutaría el paquete. (Tenga en cuenta que no puede ejecutar subpaquetes como el punto de entrada de un archivo comprimido comprimido).

Zipear una aplicación de Python:

Si tiene python3.5 +, y desea específicamente comprimir un paquete de Python, use zipapp :

$ python -m zipapp myapp $ python myapp.pyz


Aquí hay un enfoque moderno, usando pathlib, y un administrador de contexto. Coloca los archivos directamente en el zip, en lugar de en una subcarpeta.

def zip_dir(filename: str, dir_to_zip: pathlib.Path): with zipfile.ZipFile(filename, ''w'', zipfile.ZIP_DEFLATED) as zipf: # Use glob instead of iterdir(), to cover all subdirectories. for directory in dir_to_zip.glob(''**''): for file in directory.iterdir(): if not file.is_file(): continue # Strip the first component, so we don''t create an uneeded subdirectory # containing everything. zip_path = pathlib.Path(*file.parts[1:]) # Use a string, since zipfile doesn''t support pathlib directly. zipf.write(str(file), str(zip_path))


Aquí hay una variación de la respuesta dada por Nux que funciona para mí:

def WriteDirectoryToZipFile( zipHandle, srcPath, zipLocalPath = "", zipOperation = zipfile.ZIP_DEFLATED ): basePath = os.path.split( srcPath )[ 0 ] for root, dirs, files in os.walk( srcPath ): p = os.path.join( zipLocalPath, root [ ( len( basePath ) + 1 ) : ] ) # add dir zipHandle.write( root, p, zipOperation ) # add files for f in files: filePath = os.path.join( root, f ) fileInZipPath = os.path.join( p, f ) zipHandle.write( filePath, fileInZipPath, zipOperation )


Bueno, después de leer las sugerencias, se me ocurrió una forma muy similar que funciona con 2.7.x sin crear nombres de directorio "divertidos" (nombres de tipo absoluto), y solo se creará la carpeta especificada dentro del zip.

O en caso de que necesite que su zip contenga una carpeta con los contenidos del directorio seleccionado.

def zipDir( path, ziph ) : """ Inserts directory (path) into zipfile instance (ziph) """ for root, dirs, files in os.walk( path ) : for file in files : ziph.write( os.path.join( root, file ) , os.path.basename( os.path.normpath( path ) ) + "//" + file ) def makeZip( pathToFolder ) : """ Creates a zip file with the specified folder """ zipf = zipfile.ZipFile( pathToFolder + ''file.zip'', ''w'', zipfile.ZIP_DEFLATED ) zipDir( pathToFolder, zipf ) zipf.close() print( "Zip file saved to: " + pathToFolder) makeZip( "c://path//to//folder//to//insert//into//zipfile" )


Como otros han señalado, debe utilizar zipfile . La documentación le indica qué funciones están disponibles, pero realmente no explica cómo puede usarlas para comprimir un directorio completo. Creo que es más fácil de explicar con un código de ejemplo:

#!/usr/bin/env python import os import zipfile def zipdir(path, ziph): # ziph is zipfile handle for root, dirs, files in os.walk(path): for file in files: ziph.write(os.path.join(root, file)) if __name__ == ''__main__'': zipf = zipfile.ZipFile(''Python.zip'', ''w'', zipfile.ZIP_DEFLATED) zipdir(''tmp/'', zipf) zipf.close()

Adaptado de: http://www.devshed.com/c/a/Python/Python-UnZipped/


Esta función comprimirá de forma recursiva un árbol de directorios, comprimirá los archivos y registrará los nombres de archivo relativos correctos en el archivo. Las entradas del archivo son las mismas que las generadas por zip -r output.zip source_dir .

import os import zipfile def make_zipfile(output_filename, source_dir): relroot = os.path.abspath(os.path.join(source_dir, os.pardir)) with zipfile.ZipFile(output_filename, "w", zipfile.ZIP_DEFLATED) as zip: for root, dirs, files in os.walk(source_dir): # add directory (needed for empty dirs) zip.write(root, os.path.relpath(root, relroot)) for file in files: filename = os.path.join(root, file) if os.path.isfile(filename): # regular files only arcname = os.path.join(os.path.relpath(root, relroot), file) zip.write(filename, arcname)


He hecho algunos cambios en el share . La función de abajo también agregará directorios vacíos si los tiene. Los ejemplos deberían dejar más claro cuál es la ruta agregada al zip.

#!/usr/bin/env python import os import zipfile def addDirToZip(zipHandle, path, basePath=""): """ Adding directory given by /a path to opened zip file /a zipHandle @param basePath path that will be removed from /a path when adding to archive Examples: # add whole "dir" to "test.zip" (when you open "test.zip" you will see only "dir") zipHandle = zipfile.ZipFile(''test.zip'', ''w'') addDirToZip(zipHandle, ''dir'') zipHandle.close() # add contents of "dir" to "test.zip" (when you open "test.zip" you will see only it''s contents) zipHandle = zipfile.ZipFile(''test.zip'', ''w'') addDirToZip(zipHandle, ''dir'', ''dir'') zipHandle.close() # add contents of "dir/subdir" to "test.zip" (when you open "test.zip" you will see only contents of "subdir") zipHandle = zipfile.ZipFile(''test.zip'', ''w'') addDirToZip(zipHandle, ''dir/subdir'', ''dir/subdir'') zipHandle.close() # add whole "dir/subdir" to "test.zip" (when you open "test.zip" you will see only "subdir") zipHandle = zipfile.ZipFile(''test.zip'', ''w'') addDirToZip(zipHandle, ''dir/subdir'', ''dir'') zipHandle.close() # add whole "dir/subdir" with full path to "test.zip" (when you open "test.zip" you will see only "dir" and inside it only "subdir") zipHandle = zipfile.ZipFile(''test.zip'', ''w'') addDirToZip(zipHandle, ''dir/subdir'') zipHandle.close() # add whole "dir" and "otherDir" (with full path) to "test.zip" (when you open "test.zip" you will see only "dir" and "otherDir") zipHandle = zipfile.ZipFile(''test.zip'', ''w'') addDirToZip(zipHandle, ''dir'') addDirToZip(zipHandle, ''otherDir'') zipHandle.close() """ basePath = basePath.rstrip("///") + "" basePath = basePath.rstrip("///") for root, dirs, files in os.walk(path): # add dir itself (needed for empty dirs zipHandle.write(os.path.join(root, ".")) # add files for file in files: filePath = os.path.join(root, file) inZipPath = filePath.replace(basePath, "", 1).lstrip("///") #print filePath + " , " + inZipPath zipHandle.write(filePath, inZipPath)

Arriba hay una función simple que debería funcionar para casos simples. Puedes encontrar clases más elegantes en mi lista: https://gist.github.com/Eccenux/17526123107ca0ac28e6


La forma más fácil es usar shutil.make_archive . Es compatible con los formatos zip y tar.

import shutil shutil.make_archive(output_filename, ''zip'', dir_name)

Si necesita hacer algo más complicado que comprimir todo el directorio (como omitir ciertos archivos), deberá buscar en el módulo zipfile como otros lo han sugerido.


Para agregar compresión al archivo zip resultante, echa un vistazo a este enlace .

Necesitas cambiar:

zip = zipfile.ZipFile(''Python.zip'', ''w'')

a

zip = zipfile.ZipFile(''Python.zip'', ''w'', zipfile.ZIP_DEFLATED)


Para agregar el contenido de mydirectory a un nuevo archivo zip, incluidos todos los archivos y subdirectorios:

import os import zipfile zf = zipfile.ZipFile("myzipfile.zip", "w") for dirname, subdirs, files in os.walk("mydirectory"): zf.write(dirname) for filename in files: zf.write(os.path.join(dirname, filename)) zf.close()


Para dar más flexibilidad, por ejemplo, seleccione el directorio / archivo por nombre de uso

import os import zipfile def zipall(ob, path, rel=""): basename = os.path.basename(path) if os.path.isdir(path): if rel == "": rel = basename ob.write(path, os.path.join(rel)) for root, dirs, files in os.walk(path): for d in dirs: zipall(ob, os.path.join(root, d), os.path.join(rel, d)) for f in files: ob.write(os.path.join(root, f), os.path.join(rel, f)) break elif os.path.isfile(path): ob.write(path, os.path.join(rel, basename)) else: pass

Para un árbol de archivos:

. ├── dir │   ├── dir2 │   │   └── file2.txt │   ├── dir3 │   │   └── file3.txt │   └── file.txt ├── dir4 │   ├── dir5 │   └── file4.txt ├── listdir.zip ├── main.py ├── root.txt └── selective.zip

Puede, por ejemplo, seleccionar solo dir4 y root.txt :

cwd = os.getcwd() files = [os.path.join(cwd, f) for f in [''dir4'', ''root.txt'']] with zipfile.ZipFile("selective.zip", "w" ) as myzip: for f in files: zipall(myzip, f)

O simplemente listdir en el directorio de invocación de script y agregue todo desde allí:

with zipfile.ZipFile("listdir.zip", "w" ) as myzip: for f in os.listdir(): if f == "listdir.zip": # Creating a listdir.zip in the same directory # will include listdir.zip inside itself, beware of this continue zipall(myzip, f)


Preparé una función al consolidar la solución de Mark Byers con los comentarios de Reimund y Morten Zilmer (ruta relativa e incluyendo directorios vacíos). Como práctica recomendada, with se utiliza en la construcción de archivos de ZipFile.

La función también prepara un nombre de archivo zip predeterminado con el nombre de directorio comprimido y la extensión ''.zip''. Por lo tanto, funciona con un solo argumento: el directorio de origen para ser comprimido.

import os import zipfile def zip_dir(path_dir, path_file_zip=''''): if not path_file_zip: path_file_zip = os.path.join( os.path.dirname(path_dir), os.path.basename(path_dir)+''.zip'') with zipfile.ZipFile(path_file_zip, ''wb'', zipfile.ZIP_DEFLATED) as zip_file: for root, dirs, files in os.walk(path_dir): for file_or_dir in files + dirs: zip_file.write( os.path.join(root, file_or_dir), os.path.relpath(os.path.join(root, file_or_dir), os.path.join(path_dir, os.path.pardir)))


Probablemente quieras mirar el módulo zipfile ; hay documentación en zipfile .

También puede desear que os.walk() indexe la estructura del directorio.


Python moderno (3.6+) que usa el módulo pathlib para el manejo conciso de rutas OOP-like, y pathlib.Path.rglob() para el uso de globos recursivos. Por lo que puedo decir, esto es equivalente a la respuesta de George V. Reilly: cremalleras con compresión, el elemento superior es un directorio, mantiene las direcciones vacías, usa rutas relativas.

from pathlib import Path from zipfile import ZIP_DEFLATED, ZipFile from os import PathLike from typing import Union def zip_dir(zip_name: str, source_dir: Union[str, PathLike]): src_path = Path(source_dir).expanduser().resolve(strict=True) with ZipFile(zip_name, ''w'', ZIP_DEFLATED) as zf: for file in src_path.rglob(''*''): zf.write(file, file.relative_to(src_path.parent))

Nota: como indican las sugerencias de tipo opcionales, zip_name no puede ser un objeto de ruta ( se arreglaría en 3.6.2+ ).


Si desea una funcionalidad como la carpeta de compresión de cualquier administrador de archivos gráfico común, puede usar el siguiente código, usa el módulo zipfile . Usando este código, tendrá el archivo zip con la ruta como su carpeta raíz.

import os import zipfile def zipdir(path, ziph): # Iterate all the directories and files for root, dirs, files in os.walk(path): # Create a prefix variable with the folder structure inside the path folder. # So if a file is at the path directory will be at the root directory of the zip file # so the prefix will be empty. If the file belongs to a containing folder of path folder # then the prefix will be that folder. if root.replace(path,'''') == '''': prefix = '''' else: # Keep the folder structure after the path folder, append a ''/'' at the end # and remome the first character, if it is a ''/'' in order to have a path like # folder1/folder2/file.txt prefix = root.replace(path, '''') + ''/'' if (prefix[0] == ''/''): prefix = prefix[1:] for filename in files: actual_file_path = root + ''/'' + filename zipped_file_path = prefix + filename zipf.write( actual_file_path, zipped_file_path) zipf = zipfile.ZipFile(''Python.zip'', ''w'', zipfile.ZIP_DEFLATED) zipdir(''/tmp/justtest/'', zipf) zipf.close()


Tengo otro ejemplo de código que puede ayudar, usando python3, pathlib y zipfile. Debería funcionar en cualquier SO.

from pathlib import Path import zipfile from datetime import datetime DATE_FORMAT = ''%y%m%d'' def date_str(): """returns the today string year, month, day""" return ''{}''.format(datetime.now().strftime(DATE_FORMAT)) def zip_name(path): """returns the zip filename as string""" cur_dir = Path(path).resolve() parent_dir = cur_dir.parents[0] zip_filename = ''{}/{}_{}.zip''.format(parent_dir, cur_dir.name, date_str()) p_zip = Path(zip_filename) n = 1 while p_zip.exists(): zip_filename = (''{}/{}_{}_{}.zip''.format(parent_dir, cur_dir.name, date_str(), n)) p_zip = Path(zip_filename) n += 1 return zip_filename def all_files(path): """iterator returns all files and folders from path as absolute path string """ for child in Path(path).iterdir(): yield str(child) if child.is_dir(): for grand_child in all_files(str(child)): yield str(Path(grand_child)) def zip_dir(path): """generate a zip""" zip_filename = zip_name(path) zip_file = zipfile.ZipFile(zip_filename, ''w'') print(''create:'', zip_filename) for file in all_files(path): print(''adding... '', file) zip_file.write(file) zip_file.close() if __name__ == ''__main__'': zip_dir(''.'') print(''end!'')


Use shutil, que es parte del conjunto de bibliotecas estándar de python. Usar shutil es muy simple (ver código abajo):

  • 1er argumento: Nombre de archivo del archivo zip / tar resultante,
  • 2do arg: zip / tar,
  • 3er argumento: dir_name

Código:

import shutil shutil.make_archive(''/home/user/Desktop/Filename'',''zip'',''/home/username/Desktop/Directory'')


Prueba el de abajo. Funcionó para mí .

import zipfile, os zipf = "compress.zip" def main(): directory = r"Filepath" toZip(directory) def toZip(directory): zippedHelp = zipfile.ZipFile(zipf, "w", compression=zipfile.ZIP_DEFLATED ) list = os.listdir(directory) for file_list in list: file_name = os.path.join(directory,file_list) if os.path.isfile(file_name): print file_name zippedHelp.write(file_name) else: addFolderToZip(zippedHelp,file_list,directory) print "---------------Directory Found-----------------------" zippedHelp.close() def addFolderToZip(zippedHelp,folder,directory): path=os.path.join(directory,folder) print path file_list=os.listdir(path) for file_name in file_list: file_path=os.path.join(path,file_name) if os.path.isfile(file_path): zippedHelp.write(file_path) elif os.path.isdir(file_name): print "------------------sub directory found--------------------" addFolderToZip(zippedHelp,file_name,path) if __name__=="__main__": main()


# import required python modules # You have to install zipfile package using pip install import os,zipfile # Change the directory where you want your new zip file to be os.chdir(''Type your destination'') # Create a new zipfile ( I called it myfile ) zf = zipfile.ZipFile(''myfile.zip'',''w'') # os.walk gives a directory tree. Access the files using a for loop for dirnames,folders,files in os.walk(''Type your directory''): zf.write(''Type your Directory'') for file in files: zf.write(os.path.join(''Type your directory'',file))