0

I hope the title is not too confusing. Please have a look at the picture and gif below.

enter image description here

Say I had a directory like this. Now I want to zip all folders that match "cs-", "es-", "fr-", and so forth, like in the gif below:

EDIT: All folders have several more subfolders and/or files.

enter image description here

So far I managed to find all folders I want:

import zipfile, os, shutil, pprint

from pathlib import Path


userPath1 = Path(input("Please give me a path:",))

# '- set(userPath1.glob("*.*")' is deducted so that only folders (and no files) are stored in the variables
csFileServerFileList = list(set(userPath1.glob('cs-*')) - set(userPath1.glob("*.*")))
esFileServerFileList = list(set(userPath1.glob('es-*')) - set(userPath1.glob("*.*")))
frFileServerFileList = list(set(userPath1.glob('fr-*')) - set(userPath1.glob("*.*")))
itFileServerFileList = list(set(userPath1.glob('it-*')) - set(userPath1.glob("*.*")))
jaFileServerFileList = list(set(userPath1.glob('ja-*')) - set(userPath1.glob("*.*")))
nlFileServerFileList = list(set(userPath1.glob('nl-*')) - set(userPath1.glob("*.*")))
plFileServerFileList = list(set(userPath1.glob('pl-*')) - set(userPath1.glob("*.*")))
ptFileServerFileList = list(set(userPath1.glob('pt-*')) - set(userPath1.glob("*.*")))
ruFileServerFileList = list(set(userPath1.glob('ru-*')) - set(userPath1.glob("*.*")))
trFileServerFileList = list(set(userPath1.glob('tr-*')) - set(userPath1.glob("*.*")))

langFileServerList = [
                        csFileServerFileList, esFileServerFileList, frFileServerFileList, itFileServerFileList,
                        jaFileServerFileList, nlFileServerFileList, plFileServerFileList, ptFileServerFileList,
                        ruFileServerFileList, trFileServerFileList
                        ]

for list in langFileServerList:
    for i in list:
        print(i)

I know about this method:

>>> newZip = zipfile.ZipFile('new.zip', 'w')
>>> newZip.write('spam.txt', compress_type=zipfile.ZIP_DEFLATED)
>>> newZip.close()

But it only works with files and not with folders.

I'd be very grateful for your help!

1 Answers1

0

By adapting a similar question we can add directories to a zip file easily:

#!/usr/bin/env python
import os
import zipfile

def create_zip(zip_name: str, paths: list):
    # zipf is zipfile handle
    zipf = zipfile.ZipFile(zip_name, 'w', zipfile.ZIP_DEFLATED)
    # Add each file from each path
    for path in paths:
        for root, dirs, files in os.walk(path):
            for file in files:
                zipf.write(os.path.join(root, file))
    zipf.close()


if __name__ == '__main__':
    # Create a zip with both the tmp/ and tmp2/ folders called myZip.zip
    create_zip('myZip.zip', ['tmp/', 'tmp2/'])

So using your list of folders you want to zip you would be able to do:

# We need the names of our zip files somehow, here's one way
zip_names = ['cd.zip', 'es.zip', 'fr.zip', ...]

for zip_name, paths in zip(zip_names, langFileServerList):
    create_zip(zip_name, paths)

Edit (Full Working Example):

#!/usr/bin/env python
import os
import zipfile

def create_zip(zip_name: str, paths: list):
    # zipf is zipfile handle
    zipf = zipfile.ZipFile(zip_name, 'w', zipfile.ZIP_DEFLATED)
    # Add each file from each path
    for path in paths:
        for root, dirs, files in os.walk(path):
            for file in files:
                zipf.write(os.path.join(root, file))
    zipf.close()


def get_dir_list():
    # Get list of all relativ directories
    dirs = [name for name in os.listdir(".") if os.path.isdir(name)]
    # Sort by prefix
    sorted_dirs = {}
    for directory in dirs:
        # We can user the prefix as a key to croup directories together
        prefix = directory.split('-')[0]
        # Check if the key already exists in the sorted dictionary
        if prefix in sorted_dirs.keys():
            # Append the directory to the existing list
            sorted_dirs[prefix].append(directory)
        else:
            # Create the key with a list containing the directory
            sorted_dirs[prefix] = [directory]
    # Returning sorted_dirs.items() will return a list of key value pairs
    return sorted_dirs.items()



if __name__ == '__main__':
    dirs = get_dir_list()
    print(dirs)
    for lang, lang_dirs in dirs:
        create_zip(lang + ".zip", lang_dirs)
GTBebbo
  • 1,198
  • 1
  • 8
  • 17
  • Hey, thank you! The solution you gave zips everything starting from 'Users', but I'd be fine with just zipping from where the files are located. I checked the 'similar question' you posted and was wondering about a comment by another user: https://stackoverflow.com/questions/1855095/how-to-create-a-zip-archive-of-a-directory-in-python/1855118#comment25230787_1855118 . I tried to use `zipf.write(os.path.relpath(os.path.join(root, file), os.path.join(path, '..')))`as well but it doesn't work (FileNotFoundError: WinError 3). I'm at a bit of a loss. – KommissarRegEx Dec 23 '20 at 17:48
  • This may because the list of paths need to be a list of relative paths as strings – GTBebbo Dec 23 '20 at 17:51
  • I was also wondering: is this part necessary? `if __name__ == '__main__': # Create a zip with both the tmp/ and tmp2/ folders called myZip.zip create_zip('myZip.zip', ['tmp/', 'tmp2/'])` – KommissarRegEx Dec 23 '20 at 17:52
  • That part is just demonstrating how to use the `create_zip` function defined above. So no, you don't need it – GTBebbo Dec 23 '20 at 17:54
  • Thanks! "This may because the list of paths need to be a list of relative paths as strings" --> maybe it's because what I'm trying to do is above my current skill level -- but can I ask how I would do that? – KommissarRegEx Dec 23 '20 at 18:05
  • @KommissarRegEx I've added a full working example for you, in which I've added a `get_dirs_list` function that will return a list of grouped directories in the same folder as the python file. These can be used as relative paths. I've left a print statement in so you can see what `get_dirs_list` returns so you can fully understand it – GTBebbo Dec 23 '20 at 18:37