Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compressing directory using shutil.make_archive() while preserving directory structure

I'm trying to zip a directory called test_dicoms to a zip file named test_dicoms.zip using the following code:

shutil.make_archive('/home/code/test_dicoms', 'zip', '/home/code/test_dicoms') 

The problem is that when I unzip it, all of the files that were in /test_dicoms/ are extracted to /home/code/ instead of the folder /test_dicoms/ and all of it's contained files being extracted to /home/code/. So /test_dicoms/ has a file called foo.txt and after I zip and unzip foo.txt's path is /home/code/foo.txt as opposed to /home/code/test_dicoms/foo.txt. How do I fix this? Also, some of the directories I'm working with are very large. Will I need to add anything to my code to make it ZIP64 or is the function smart enough to do that automatically?

Here's what's currently in the archive created:

[gwarner@jazz gwarner]$ unzip -l test_dicoms.zip Archive: test_dicoms.zip Length    Date       Time  Name --------- ---------- ----- ----     93324 09-17-2015 16:05 AAscout_b_000070     93332 09-17-2015 16:05 AAscout_b_000125     93332 09-17-2015 16:05 AAscout_b_000248 
like image 672
G Warner Avatar asked Sep 17 '15 21:09

G Warner


People also ask

What is Root_dir?

root_dir refers to base directory of output file, or working directory for your working script.

Is Shutil thread safe?

shutil. make_archive() is not thread-safe. The reason for it is that it changes the current working directory, which is global for the process. Threads don't have their own working directory.


2 Answers

Using the terms in the documentation, you have specified a root_dir, but not a base_dir. Try specifying the base_dir like so:

shutil.make_archive('/home/code/test_dicoms',                     'zip',                     '/home/code/',                     'test_dicoms') 

To answer your second question, it depends upon the version of Python you are using. Starting from Python 3.4, ZIP64 extensions will be availble by default. Prior to Python 3.4, make_archive will not automatically create a file with ZIP64 extensions. If you are using an older version of Python and want ZIP64, you can invoke the underlying zipfile.ZipFile() directly.

If you choose to use zipfile.ZipFile() directly, bypassing shutil.make_archive(), here is an example:

import zipfile import os  d = '/home/code/test_dicoms'  os.chdir(os.path.dirname(d)) with zipfile.ZipFile(d + '.zip',                      "w",                      zipfile.ZIP_DEFLATED,                      allowZip64=True) as zf:     for root, _, filenames in os.walk(os.path.basename(d)):         for name in filenames:             name = os.path.join(root, name)             name = os.path.normpath(name)             zf.write(name, name) 

Reference:

  • https://docs.python.org/library/shutil.html#shutil.make_archive
  • https://docs.python.org/library/zipfile.html#zipfile-objects
like image 193
Robᵩ Avatar answered Sep 18 '22 12:09

Robᵩ


I have written a wrapper function myself because shutil.make_archive is too confusing to use.

Here it is http://www.seanbehan.com/how-to-use-python-shutil-make_archive-to-zip-up-a-directory-recursively-including-the-root-folder/

And just the code..

import os, shutil def make_archive(source, destination):         base = os.path.basename(destination)         name = base.split('.')[0]         format = base.split('.')[1]         archive_from = os.path.dirname(source)         archive_to = os.path.basename(source.strip(os.sep))         shutil.make_archive(name, format, archive_from, archive_to)         shutil.move('%s.%s'%(name,format), destination)  make_archive('/path/to/folder', '/path/to/folder.zip') 
like image 44
seanbehan Avatar answered Sep 20 '22 12:09

seanbehan