¿Cómo creo un archivo zip de una ruta de archivo con Python, incluidos los directorios vacíos?

He estado tratando de usar los módulos zipfile y shutil.make_archive para crear recursivamente un archivo zip de un directorio. Ambos módulos funcionan muy bien, excepto que los directorios vacíos no se agregan al archivo. Los directorios vacíos que contienen otros directorios vacíos también se omiten silenciosamente.

Puedo usar 7Zip para crear un archivo de la misma ruta y se conservan los directorios vacíos. Por lo tanto, sé que esto es posible dentro del propio formato de archivo. Simplemente no sé cómo hacerlo dentro de Python. ¿Algunas ideas? ¡Gracias!

Hay un ejemplo usando zipfile:

 import os, zipfile from os.path import join def zipfolder(foldername, filename, includeEmptyDIr=True): empty_dirs = [] zip = zipfile.ZipFile(filename, 'w', zipfile.ZIP_DEFLATED) for root, dirs, files in os.walk(foldername): empty_dirs.extend([dir for dir in dirs if os.listdir(join(root, dir)) == []]) for name in files: zip.write(join(root ,name)) if includeEmptyDIr: for dir in empty_dirs: zif = zipfile.ZipInfo(join(root, dir) + "/") zip.writestr(zif, "") empty_dirs = [] zip.close() if __name__ == "__main__": zipfolder('test1/noname/', 'zip.zip') 

Deberá registrar un nuevo formato de archivo para hacerlo, ya que el archivador ZIP predeterminado no lo admite. Eche un vistazo a la carne del archivador ZIP existente . Cree su propio archivador que cree directorios utilizando esa variable dirpath no utilizada dirpath . Busqué cómo crear un directorio vacío y encontré esto :

 zip.writestr(zipfile.ZipInfo('empty/'), '') 

Con eso, deberías poder escribir el código necesario para hacerlo archivar directorios vacíos.

Esto se levanta desde Agregar carpetas a un archivo zip usando python, pero es la única función que he probado que funciona. El que aparece como la respuesta no funciona en Python 2.7.3 (no copia los directorios vacíos y es ineficiente). Lo siguiente está probado y probado:

 #!/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()