How To Zip Folder in Python


Bismillah

How if you want to provide your user a list of files in your backend server, and you want to provide them a zip file generated on the fly?

This article will cover that using python, and django framework. Let's dive in.


You can use ZipFile library to handle such condition. The constructor need a required parameter called file. The file parameter can be: - a string. If a string provided, then ZipFile will use it as a path. - a File object - a file like object - a path file like object

And the second parameter was an opening mode flag. Think like open library. r for read, and w as write, etc...

and also, you can use instance of ZipFile as context manager. That means if you go outside the with block, the zip file will be closed automatically.


Let's try to create a zip file from a folder. Supposed you have tree like this

folder
- audio1
- audio2
- audio3

After creating a ZipFile instance, you can use method write that accept filename parameter.

In the following example, you can see I use the arcname parameter. This is optional. If not specified, the filename inside the zip file will match filename and stored in the one level.

But, if you want to persist the directory structure, you should specify this.

import os
from zipfile import ZipFile

# we assume that the active directory was 
# same level with the `folder`

with ZipFile('folder.zip', mode='r') as compressor:
    for f in os.listdir("folder"):
        compressor.write(f, arcname=f)

Okay, that's enough. Let's use it in django. You may thinking to create a temporary file using tempfile library.

But, think again!

Django's Response was a File like object. You can use it as first parameter of ZipFile instead of create a temp file, then deleting it.

    files = ["abc.txt", "def.txt", "ghi.txt"]

    response = HttpResponse(
        content_type="application/zip",
        headers={
            "Content-Disposition": f"attachment; filename=helloworld.zip"
        }
    )

    with zipfile.ZipFile(response, "w") as compressor:
        for file in files:
            compressor.write(default_storage.path(f"{file}"), arcname=file)

    return response

That's it.


Refs:

  • https://docs.python.org/3/library/zipfile.html
  • https://docs.djangoproject.com/en/4.1/howto/outputting-csv