Agregando carpetas a un archivo zip usando python

Quiero crear un archivo zip. Agregue una carpeta al archivo zip y luego agregue un montón de archivos a esa carpeta.

Así que quiero terminar con un archivo zip con una sola carpeta con archivos en.

No sé si es una mala práctica tener carpetas en archivos zip o algo así, pero Google no me da nada sobre el tema.

Comencé con esto:

def addFolderToZip(myZipFile,folder): folder = folder.encode('ascii') #convert path to ascii for ZipFile Method for file in glob.glob(folder+"/*"): if os.path.isfile(file): print file myZipFile.write(file, os.path.basename(file), zipfile.ZIP_DEFLATED) elif os.path.isdir(file): addFolderToZip(myZipFile,file) def createZipFile(filename,files,folders): curTime=strftime("__%Y_%m_%d", time.localtime()) filename=filename+curTime; print filename zipFilename=utils.getFileName("files", filename+".zip") myZipFile = zipfile.ZipFile( zipFilename, "w" ) # Open the zip file for writing for file in files: file = file.encode('ascii') #convert path to ascii for ZipFile Method if os.path.isfile(file): (filepath, filename) = os.path.split(file) myZipFile.write( file, filename, zipfile.ZIP_DEFLATED ) for folder in folders: addFolderToZip(myZipFile,folder) myZipFile.close() return (1,zipFilename) (success,filename)=createZipFile(planName,files,folders); 

Tomado de: http://mail.python.org/pipermail/python-list/2006-August/396166.html

Lo que elimina todas las carpetas y coloca todos los archivos en la carpeta de destino (y sus subcarpetas) en un solo archivo zip. No pude conseguirlo para agregar una carpeta completa.

Si paso la ruta a una carpeta en myZipFile.write, obtengo

IOError: [Errno 13] Permiso denegado: ‘.. \ packed \ bin’

Cualquier ayuda es muy bienvenida.

Pregunta relacionada: ¿Cómo puedo comprimir el contenido de una carpeta usando python (versión 2.5)?

Bien, después de que entendí lo que quieres, es tan simple como usar el segundo argumento de zipfile.write , donde puedes usar lo que quieras:

 import zipfile myZipFile = zipfile.ZipFile("zip.zip", "w" ) myZipFile.write("test.py", "dir\\test.py", zipfile.ZIP_DEFLATED ) 

crea un archivo zip donde test.py se extraería a un directorio llamado dir

EDITAR: Una vez tuve que crear un directorio vacío en un archivo zip: es posible. después de que el código anterior simplemente elimine el archivo test.py del archivo zip, el archivo desaparece, pero el directorio vacío permanece.

También puedes usar shutil.

 import shutil zip_name = 'path\to\zip_file' directory_name = 'path\to\directory' # Create 'path\to\zip_file.zip' shutil.make_archive(zip_name, 'zip', directory_name) 

Esto pondrá toda la carpeta en el zip.

Un archivo zip no tiene una estructura de directorio, solo tiene un montón de rutas y su contenido. Estas rutas de acceso deben ser relativas a una carpeta raíz imaginaria (el propio archivo ZIP). Los prefijos “../” no tienen un significado definido en un archivo zip.

Considere que tiene un archivo, y quiere almacenarlo en una “carpeta” dentro de un archivo zip. Todo lo que tiene que hacer es prefijar el nombre del archivo con un nombre de carpeta al almacenar el archivo en el archivo zip:

 zipi= zipfile.ZipInfo() zipi.filename= "folder/a" # this is what you want zipi.date_time= time.localtime(os.path.getmtime("a"))[:6] zipi.compress_type= zipfile.ZIP_DEFLATED filedata= open("a", "rb").read() zipfile1.writestr(zipi, filedata) # zipfile1 is a zipfile.ZipFile instance 

No sé de ninguna implementación ZIP que permita la inclusión de una carpeta vacía en un archivo ZIP. Se me ocurre una solución alternativa (almacenar un nombre de archivo ficticio en la “carpeta” zip que debería ignorarse en la extracción), pero no se puede trasladar a todas las implementaciones.

 import zipfile import os class ZipUtilities: def toZip(self, file, filename): zip_file = zipfile.ZipFile(filename, 'w') if os.path.isfile(file): zip_file.write(file) else: self.addFolderToZip(zip_file, file) zip_file.close() def addFolderToZip(self, zip_file, folder): for file in os.listdir(folder): full_path = os.path.join(folder, file) if os.path.isfile(full_path): print 'File added: ' + str(full_path) zip_file.write(full_path) elif os.path.isdir(full_path): print 'Entering folder: ' + str(full_path) self.addFolderToZip(zip_file, full_path) def main(): utilities = ZipUtilities() filename = 'TEMP.zip' directory = 'TEMP' utilities.toZip(directory, filename) main() 

Estoy corriendo:

 python tozip.py 

Este es el registro:

 havok@fireshield:~$ python tozip.py File added: TEMP/NARF (7ª copia) Entering folder: TEMP/TEMP2 File added: TEMP/TEMP2/NERF (otra copia) File added: TEMP/TEMP2/NERF (copia) File added: TEMP/TEMP2/NARF File added: TEMP/TEMP2/NARF (copia) File added: TEMP/TEMP2/NARF (otra copia) Entering folder: TEMP/TEMP2/TEMP3 File added: TEMP/TEMP2/TEMP3/DOCUMENTO DEL FINAL File added: TEMP/TEMP2/TEMP3/DOCUMENTO DEL FINAL (copia) File added: TEMP/TEMP2/NERF File added: TEMP/NARF (copia) (otra copia) File added: TEMP/NARF (copia) (copia) File added: TEMP/NARF (6ª copia) File added: TEMP/NERF (copia) (otra copia) File added: TEMP/NERF (4ª copia) File added: TEMP/NERF (otra copia) File added: TEMP/NERF (3ª copia) File added: TEMP/NERF (6ª copia) File added: TEMP/NERF (copia) File added: TEMP/NERF (5ª copia) File added: TEMP/NARF (8ª copia) File added: TEMP/NARF (3ª copia) File added: TEMP/NARF (5ª copia) File added: TEMP/NERF (copia) (3ª copia) File added: TEMP/NARF File added: TEMP/NERF (copia) (copia) File added: TEMP/NERF (8ª copia) File added: TEMP/NERF (7ª copia) File added: TEMP/NARF (copia) File added: TEMP/NARF (otra copia) File added: TEMP/NARF (4ª copia) File added: TEMP/NERF File added: TEMP/NARF (copia) (3ª copia) 

Como puede ver, funciona, el archivo también está bien. Esta es una función recursiva que puede comprimir una carpeta completa. El único problema es que no crea una carpeta vacía.

Aclamaciones.

A continuación hay un código para comprimir un directorio completo en un archivo zip.

Esto parece funcionar bien creando archivos zip en Windows y Linux. Los archivos de salida parecen extraerse correctamente en Windows (función de Carpetas comprimidas incorporadas, WinZip y 7-Zip) y Linux. Sin embargo, los directorios vacíos en un archivo zip parecen ser un problema espinoso. La solución a continuación parece funcionar pero la salida de “zipinfo” en linux es preocupante. Además, los permisos de directorio no están configurados correctamente para directorios vacíos en el archivo zip. Esto parece requerir un poco más de investigación en profundidad.

Obtuve algo de información de este hilo de revisiones de velocidad y este hilo de la lista de correo de Python .

Tenga en cuenta que esta función está diseñada para colocar archivos en el archivo zip sin ningún directorio principal o solo un directorio principal, por lo que recortará los directorios principales en las rutas del sistema de archivos y no los incluirá dentro de las rutas del archivo zip. Este es generalmente el caso cuando solo desea tomar un directorio y convertirlo en un archivo zip que se pueda extraer en diferentes ubicaciones.

Argumentos de palabras clave:

dirPath – cadena de ruta al directorio para archivar. Este es el único argumento requerido. Puede ser absoluto o relativo, pero solo se incluirán uno o ninguno de los directorios principales en el archivo zip.

zipFilePath: ruta de acceso de cadena al archivo zip de salida. Esto puede ser una ruta absoluta o relativa. Si el archivo zip ya existe, se actualizará. Si no, será creado. Si desea reemplazarlo desde cero, elimínelo antes de llamar a esta función. (el valor predeterminado se calcula como dirPath + “.zip”)

includeDirInZip: booleano que indica si el directorio de nivel superior se debe incluir en el archivo o se debe omitir. (Verdadero por defecto)

(Tenga en cuenta que StackOverflow parece no estar imprimiendo bastante mi python con cadenas entre comillas triples, así que simplemente convertí mis cadenas de documentos al texto de la publicación aquí)

 #!/usr/bin/python import os import zipfile def zipdir(dirPath=None, zipFilePath=None, includeDirInZip=True): if not zipFilePath: zipFilePath = dirPath + ".zip" if not os.path.isdir(dirPath): raise OSError("dirPath argument must point to a directory. " "'%s' does not." % dirPath) parentDir, dirToZip = os.path.split(dirPath) #Little nested function to prepare the proper archive path def trimPath(path): archivePath = path.replace(parentDir, "", 1) if parentDir: archivePath = archivePath.replace(os.path.sep, "", 1) if not includeDirInZip: archivePath = archivePath.replace(dirToZip + os.path.sep, "", 1) return os.path.normcase(archivePath) outFile = zipfile.ZipFile(zipFilePath, "w", compression=zipfile.ZIP_DEFLATED) for (archiveDirPath, dirNames, fileNames) in os.walk(dirPath): for fileName in fileNames: filePath = os.path.join(archiveDirPath, fileName) outFile.write(filePath, trimPath(filePath)) #Make sure we get empty directories as well if not fileNames and not dirNames: zipInfo = zipfile.ZipInfo(trimPath(archiveDirPath) + "/") #some web sites suggest doing #zipInfo.external_attr = 16 #or #zipInfo.external_attr = 48 #Here to allow for inserting an empty directory. Still TBD/TODO. outFile.writestr(zipInfo, "") outFile.close() 

Aquí hay algunos ejemplos de usos. Tenga en cuenta que si su argumento dirPath tiene varios directorios principales, solo el ÚLTIMO se incluirá de forma predeterminada. Pase includeDirInZip = False para omitir todos los directorios principales.

 zipdir("foo") #Just give it a dir and get a .zip file zipdir("foo", "foo2.zip") #Get a .zip file with a specific file name zipdir("foo", "foo3nodir.zip", False) #Omit the top level directory zipdir("../test1/foo", "foo4nopardirs.zip") 

Esta es mi función que utilizo para comprimir una carpeta:

 import os import os.path import zipfile def zip_dir(dirpath, zippath): fzip = zipfile.ZipFile(zippath, 'w', zipfile.ZIP_DEFLATED) basedir = os.path.dirname(dirpath) + '/' for root, dirs, files in os.walk(dirpath): if os.path.basename(root)[0] == '.': continue #skip hidden directories dirname = root.replace(basedir, '') for f in files: if f[-1] == '~' or (f[0] == '.' and f != '.htaccess'): #skip backup files and all hidden files except .htaccess continue fzip.write(root + '/' + f, dirname + '/' + f) fzip.close() 

después de agregar algunas importaciones, su código funciona bien para mí, ¿cómo llama a la secuencia de comandos? Tal vez podría decirnos la estructura de carpetas del directorio ‘.. \ packed \ bin’.

Llamé a tu código con los siguientes argumentos:

 planName='test.zip' files=['z.py',] folders=['c:\\temp'] (success,filename)=createZipFile(planName,files,folders) 

`

Si observa un archivo zip creado con Info-ZIP, verá que los directorios están listados:

 $ zip foo.zip -r foo adding: foo/ (stored 0%) adding: foo/foo.jpg (deflated 84%) $ less foo.zip Archive: foo.zip Length Method Size Cmpr Date Time CRC-32 Name -------- ------ ------- ---- ---------- ----- -------- ---- 0 Stored 0 0% 2013-08-18 14:32 00000000 foo/ 476320 Defl:N 77941 84% 2013-08-18 14:31 55a52268 foo/foo.jpg -------- ------- --- ------- 476320 77941 84% 2 files 

Observe que la entrada del directorio tiene longitud cero y no está comprimida. Parece que puedes lograr lo mismo con Python escribiendo el directorio por nombre, pero forzándolo a no usar la compresión.

 if os.path.isdir(name): zf.write(name, arcname=arcname, compress_type=zipfile.ZIP_STORED) else: zf.write(name, arcname=arcname, compress_type=zipfile.ZIP_DEFLATED) 

Podría valer la pena asegurarse de que arcname termine en un / .

Aquí está el código editado que corrí. Se basa en el código anterior, tomado de la lista de correo. Agregué las importaciones e hice una rutina principal. También recorté el problema con el nombre del archivo de salida para acortar el código.

 #!/usr/bin/env python import os, zipfile, glob, sys def addFolderToZip(myZipFile,folder): folder = folder.encode('ascii') #convert path to ascii for ZipFile Method for file in glob.glob(folder+"/*"): if os.path.isfile(file): print file myZipFile.write(file, os.path.basename(file), zipfile.ZIP_DEFLATED) elif os.path.isdir(file): addFolderToZip(myZipFile,file) def createZipFile(filename,files,folders): myZipFile = zipfile.ZipFile( filename, "w" ) # Open the zip file for writing for file in files: file = file.encode('ascii') #convert path to ascii for ZipFile Method if os.path.isfile(file): (filepath, filename) = os.path.split(file) myZipFile.write( file, filename, zipfile.ZIP_DEFLATED ) for folder in folders: addFolderToZip(myZipFile,folder) myZipFile.close() return (1,filename) if __name__=="__main__": #put everything in sys.argv[1] in out.zip, skip files print createZipFile("out.zip", [], sys.argv[1]) 

En el trabajo, en mi caja de Windows, este código funcionó bien pero no creó ninguna “carpeta” en el archivo zip. Al menos lo recuerdo. Ahora en casa, en mi caja de Linux, el archivo zip creado parece estar mal:

 $ unzip -l out.zip Archive: out.zip End-of-central-directory signature not found. Either this file is not a zipfile, or it constitutes one disk of a multi-part archive. In the latter case the central directory and zipfile comment will be found on the last disk(s) of this archive. unzip: cannot find zipfile directory in one of out.zip or out.zip.zip, and cannot find out.zip.ZIP, period. 

No sé si accidentalmente rompí el código, creo que es lo mismo. ¿Problemas de multiplataforma? De cualquier manera, no está relacionado con mi pregunta original; obteniendo carpetas en el archivo zip. Solo quería publicar el código que ejecuté, no el código en el que basé mi código.

¡Muchas gracias por esta útil función! Lo encontré muy útil ya que también estaba buscando ayuda. Sin embargo, tal vez sería útil cambiarlo un poco para que

 basedir = os.path.dirname(dirpath) + '/' 

sería

 basedir = os.path.dirname(dirpath + '/') 

Porque descubrí que si quiero comprimir la carpeta ‘Ejemplo’ que se encuentra en ‘C: \ folder \ ruta \ notWanted \ to \ zip \ Example’,

Me metí en Windows:

 dirpath = 'C:\folder\path\notWanted\to\zip\Example' basedir = 'C:\folder\path\notWanted\to\zip\Example/' dirname = 'C:\folder\path\notWanted\to\zip\Example\Example\Subfolder_etc' 

Pero supongo que tu código debería dar

 dirpath = 'C:\folder\path\notWanted\to\zip\Example' basedir = 'C:\folder\path\notWanted\to\zip\Example\' dirname = '\Subfolder_etc' 
 import os import zipfile zf = zipfile.ZipFile("file.zip", "w") for file in os.listdir(os.curdir): if not file.endswith('.zip') and os.path.isfile(os.curdir+'/'+file): print file zf.write(file) elif os.path.isdir(os.curdir+'/'+file): print f for f in os.listdir(os.curdir+'/'+file): zf.write(file+'\\'+f) zf.close() 

Cuando quieras crear una carpeta vacía, puedes hacerlo así:

  storage = api.Storage.open("empty_folder.zip","w") res = storage.open_resource("hannu//","w") storage.close() 

La carpeta no se muestra en winextractor, pero cuando la extraes se muestra.