Cómo imprimir el porcentaje de compresión de un archivo python

Me gustaría obtener el porcentaje en el que se encuentra un archivo mientras se comprime. Por ejemplo, imprimirá 1%, 2%, 3%, etc. No tengo idea de por dónde empezar. ¿Cómo podría hacer esto ahora? Solo tengo el código para comprimir el archivo.

Código:

zipPath = zipfile.ZipFile("Files/Zip/" + pic + ".zip", "w") for root, dirs, files in os.walk(filePath): for file in files: zipPath.write(os.path.join(root, file), str(pic) + "\\" + file) print("Done") zipPath.close() 

Desafortunadamente, no puede avanzar en la compresión de cada archivo individual desde el módulo zipfile, pero puede tener una idea del progreso total al hacer un seguimiento de cuántos bytes ha procesado hasta ahora.

Como sugirió Mikko Ohtamaa, la forma más sencilla de hacerlo es recorrer la lista de archivos dos veces, primero para determinar el tamaño de los archivos y segundo para hacer la compresión. Sin embargo, como Kevin mencionó, el contenido del directorio podría cambiar entre estos dos pasos, por lo que los números pueden ser inexactos.

El siguiente progtwig (escrito para Python 2.6) ilustra el proceso.

 #!/usr/bin/env python ''' zip all the files in dirname into archive zipname Use only the last path component in dirname as the archive directory name for all files Written by PM 2Ring 2015.02.15 From http://stackoverflow.com/q/28522669/4014959 ''' import sys import os import zipfile def zipdir(zipname, dirname): #Get total data size in bytes so we can report on progress total = 0 for root, dirs, files in os.walk(dirname): for fname in files: path = os.path.join(root, fname) total += os.path.getsize(path) #Get the archive directory name basename = os.path.basename(dirname) z = zipfile.ZipFile(zipname, 'w', zipfile.ZIP_DEFLATED) #Current data byte count current = 0 for root, dirs, files in os.walk(dirname): for fname in files: path = os.path.join(root, fname) arcname = os.path.join(basename, fname) percent = 100 * current / total print '%3d%% %s' % (percent, path) z.write(path, arcname) current += os.path.getsize(path) z.close() def main(): if len(sys.argv) < 3: print 'Usage: %s zipname dirname' % sys.argv[0] exit(1) zipname = sys.argv[1] dirname = sys.argv[2] zipdir(zipname, dirname) if __name__ == '__main__': main() 

Tenga en cuenta que abro el archivo zip con el argumento de compresión zipfile.ZIP_DEFLATED ; el valor predeterminado es zipfile.ZIP_STORED , es decir, no se realiza ninguna compresión. Además, los archivos zip pueden manejar separadores de ruta tanto de estilo DOS como de estilo Unix, por lo que no es necesario usar barras diagonales inversas en sus rutas de archivo, y como mi código muestra, puede usar os.path.join() para construir El archivo de ruta de acceso.


Por cierto, en su código tiene str(pic) dentro de su bucle interno for . En general, es un desperdicio reevaluar una función con un argumento constante dentro de un bucle. Pero en este caso, es totalmente superfluo, ya que de su primera statement parece que pic ya es una cadena.

La respuesta existente solo funciona a nivel de archivo, es decir, si tiene un solo archivo enorme para comprimir, no verá ningún progreso hasta que finalice la operación completa. En mi caso, solo tuve un archivo enorme, e hice algo como esto:

 import os import types import zipfile from functools import partial if __name__ == '__main__': out_file = "out.bz2" in_file = "/path/to/file/to/zip" def progress(total_size, original_write, self, buf): progress.bytes += len(buf) progress.obytes += 1024 * 8 # Hardcoded in zipfile.write print("{} bytes written".format(progress.bytes)) print("{} original bytes handled".format(progress.obytes)) print("{} % done".format(int(100 * progress.obytes / total_size))) return original_write(buf) progress.bytes = 0 progress.obytes = 0 with zipfile.ZipFile(out_file, 'w', compression=zipfile.ZIP_DEFLATED) as _zip: # Replace original write() with a wrapper to track progress _zip.fp.write = types.MethodType(partial(progress, os.path.getsize(in_file), _zip.fp.write), _zip.fp) _zip.write(in_file) 

No es óptimo ya que hay un número codificado de bytes manejados por llamada a write () que podrían cambiar.

Además, la función se llama con bastante frecuencia, la actualización de una interfaz de usuario probablemente no debería realizarse para cada llamada.