Member Avatar for Member #1110403

I asked this question on StackOverflow and they just linked me to other questions that I already read and tried.

I have been trying to create a zip file using zipfile in Python, but it keeps zipping all folders that are included in the absolute path. I just want to zip the file that the path leads to, not all of the files in that path.

If I try to create a zip file named "Zip_Files.zip" from this path:

C:\Users\UserName\Documents\Folder_to_be_zipped\

When I try to zip this I end up with a zip folder like this:

Zip_Files -> Users -> UserName -> Documents -> Folder_to_be_zipped -> {contents of Folder_to_be_zipped}

I want something like this:

Zip_Files.zip -> Folder_to_be_zipped -> {contents of Folder_to_be_zipped}

I only want to zip Folder_to_be_zipped, not every file leading to that folder.

This code gives me the Zip_Files.zip -> Folder_to_be_zipped but there's nothing inside of Folder_to_be_zipped and I know that's because zipfile isn't recursive.

from os.path import basename
...
zip.write(first_path, basename(first_path))
zip.write(second_path, basename(second_path))
zip.close()

This code gives me Zip_Files.zip -> Users -> UserName -> Documents -> Folder_to_be_zipped -> {contents of Folder_to_be_zipped}

import os
import zipfile

def zipdir(path, zip):
    for root, dirs, files in os.walk(path):
        for file in files:
            zip.write(os.path.join(root, file))

if __name__ == '__main__':
    zipf = zipfile.ZipFile('Python.zip', 'w')
    zipdir('C:/Users/UserName/Documents/Folder_to_be_zipped/', zipf)
    zipf.close()

So I know that my solution is somewhere in the middle of these two pieces of code, but I am relatively new to Python and I can't figure it out. Hopefully you guys can give me the code to make this work.

Dani AI

Generated

zipfile stores exactly the path you give it. To avoid embedding the absolute path, compute a relative path and pass it as arcname to ZipFile.write(). If you make the relative path start at the parent of the folder you want to zip, the archive will contain Folder_to_be_zipped/... at the top level.

import os
import zipfile

def zip_folder(src_dir, zip_path):
    src_dir = os.path.normpath(src_dir)
    parent = os.path.dirname(src_dir)            # parent of Folder_to_be_zipped
    with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zf:
        for root, _, files in os.walk(src_dir):
            for name in files:
                full = os.path.join(root, name)
                arc = os.path.relpath(full, start=parent)
                zf.write(full, arc)              # arc == 'Folder_to_be_zipped/...'

This approach avoids changing the working directory and works cross-platform. Note that you do not need to add an explicit directory entry; extractors will create directories as needed.

For one-liners, shutil.make_archive can also do this correctly:
shutil.make_archive('Zip_Files', 'zip', root_dir=parent, base_dir=os.path.basename(src_dir)).

See the official docs for details on arcname in ZipFile.write and root_dir/base_dir in shutil.make_archive.

Did you try

    oldwd = os.getcwd()
    os.chdir('C:/Users/UserName/Documents')
    try:
        zipdir('Folder_to_be_zipped', zipf)
    finally:
        os.chdir(oldwd)

?

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.