Senderos de archivo diferentes en Python ZipFile Dependiendo de .write() vs .writestr()

Sólo quería preguntar rápidamente si se espera que el comportamiento que veo en el módulo de archivo postal de Python... Quería armar un archivo postal. Por razones que no creo que necesite entrar, estaba añadiendo algunos archivos usando zipfile.writestr() y otros usando .write(). Estaba escribiendo algunos archivos al subdirectorio zip llamado /scripts y otros a un subdirectorio zip llamado /data.

Para /data, originalmente hice esto:

for root, _, filenames in os.walk(tmpdirname):
    for root_name in filenames:
        print(f"Handle zip of {root_name}")
        name = os.path.join(root, root_name)
        name = os.path.normpath(name)
        zipFile.write(name, f'/data/{root_name}')

Esto funcionó bien y produjo un archivo de trabajo que pude extraer. Hasta ahora, muy bien. Para escribir archivos de texto al subdirectorio /script, usé:

zipFile.writestr(f'/script/{scriptname}', fileBytes)

De nuevo, hasta ahora tan bien.

Ahora se pone raro... Quería extraer archivos en /data/. Así que busqué caminos en zipFile.namelist() comenzando con /data. Mi código siguió perdiendo los archivos en /data/, sin embargo. Haciendo algo más de excavación, noté que los archivos escritos usando .writestr tenían un slash al comienzo de la ruta del archivo zip como este: "/scripts/myscript.py". Los archivos escritos usando .write no tener un corte en el comienzo de la ruta, por lo que las rutas del archivo de datos parecían así: "data/mydata.pickle".

Cambié mi código para usar .writestr() para los archivos de datos:

for root, _, filenames in os.walk(tmpdirname):
    for root_name in filenames:
        print(f"Handle zip of {root_name}")
        name = os.path.join(root, root_name)
        name = os.path.normpath(name)
        with open(name, mode='rb') as extracted_file:
            zipFile.writestr(f'/data/{root_name}', extracted_file.read())

Voila, los archivos de datos ahora tienen slashes al comienzo de la ruta. No estoy seguro de por qué, sin embargo, ya que estoy proporcionando la misma ruta de archivo de cualquier manera, y no esperaría usar un método contra otro cambiaría los caminos.

¿Se supone que esto funcione de esta manera? ¿Me estoy perdiendo algo obvio aquí?

Pregunta hecha hace 3 años, 5 meses, 0 días - Por algorithmadept


2 Respuestas:

  • El comportamiento que estás experimentando es porque zipfile.write() espera una ruta de archivo relativa en el archivo ZIP, mientras que zipfile.writestr() simplemente toma un nombre de archivo en el archivo ZIP sin considerar si comienza con una barra inclinada o no.

    Cuando usas zipfile.write(), estás especificando la ruta relativa en el archivo ZIP, por lo que el archivo se guarda correctamente en la carpeta /data/ en el archivo ZIP. En cambio, al utilizar zipfile.writestr(), estás proporcionando directamente el nombre del archivo en el archivo ZIP, por lo que incluir o no una barra inclinada al principio no afectará su ubicación en el archivo ZIP.

    Para mantener la consistencia en la estructura de carpetas dentro del archivo ZIP y evitar confusiones al extraer los archivos, es recomendable usar la misma convención de rutas (con o sin barra inclinada al principio) al agregar archivos al archivo ZIP. En tu caso, parece que el cambio a usar zipfile.writestr() para los archivos de datos ha resuelto el problema y ahora los archivos se guardan correctamente en la carpeta /data/.

    En resumen, la diferencia en el comportamiento se debe a cómo las funciones write() y writestr() interpretan las rutas de archivo al agregar archivos al archivo ZIP.

    Respondida el Dec 18, 2020 a las 02:26 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • Comportamiento esperado:

    Sí, el comportamiento que observas es el esperado. El método writestr() crea un nuevo archivo en el archivo ZIP con una ruta absoluta, mientras que write() añade un archivo existente a un archivo ZIP con una ruta relativa.

    Diferencia entre rutas absolutas y relativas:

    Ruta absoluta: Comienza con una barra inclinada (/) y especifica la ruta completa desde la raíz del archivo ZIP. Ruta relativa: No comienza con una barra inclinada y especifica la ruta relativa al directorio actual dentro del archivo ZIP.

    Razón del comportamiento:

    Cuando utilizas writestr(), estás creando un nuevo archivo en el archivo ZIP, por lo que la ruta que proporcionas debe ser una ruta absoluta para identificar de forma única el archivo dentro del archivo ZIP. Cuando utilizas write(), estás añadiendo un archivo existente al archivo ZIP, por lo que la ruta que proporcionas debe ser una ruta relativa para especificar dónde colocar el archivo dentro del archivo ZIP.

    Solución:

    Para resolver este problema, puedes utilizar writestr() para todos los archivos, incluso para los archivos de datos. Esto garantizará que todos los archivos tengan rutas absolutas y se puedan extraer correctamente del archivo ZIP.

    Código actualizado:

    python
    for root, _, filenames in os.walk(tmpdirname):
        for root_name in filenames:
            print(f"Handle zip of {root_name}")
            name = os.path.join(root, root_name)
            name = os.path.normpath(name)
            with open(name, mode='rb') as extracted_file:
                zipFile.writestr(f'/data/{root_name}', extracted_file.read())
    

    Respondida el Dec 18, 2020 a las 02:31 - por Gemini

    Votos positivos: 0 | Votos negativos: 0