Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python zip folder without including './' (current directory)

Tags:

python

zip

I'm trying to zip the content of the test folder:

first.txt
pof/
pof/second.txt

If I cd into test then zip it using

zip -r folder.zip *

and check the resulting archive with

zipinfo folder.zip

I get this output:

Archive:  folder.zip
Zip file size: 7573 bytes, number of entries: 3
-rw-r--r--  3.0 unx     6473 tx defN 16-Mar-11 10:19 first.txt
drwxr-xr-x  3.0 unx        0 bx stor 16-Mar-11 10:20 pof/
-rw-r--r--  3.0 unx     2841 tx defN 16-Mar-11 10:20 pof/second.txt
3 files, 9314 bytes uncompressed, 7113 bytes compressed:  23.6%

Everything seems to be working as expected but if I zip the same folder using

shutil.make_archive('folder', 'zip', 'test')

then check the archive with

zipinfo folder.zip

I get this output:

Archive:  folder.zip
Zip file size: 7497 bytes, number of entries: 4
drwxr-xr-x  2.0 unx        0 b- defN 16-Mar-11 10:28 ./
drwxr-xr-x  2.0 unx        0 b- defN 16-Mar-11 10:20 pof/
-rw-r--r--  2.0 unx     6473 b- defN 16-Mar-11 10:19 first.txt
-rw-r--r--  2.0 unx     2841 b- defN 16-Mar-11 10:20 pof/second.txt
4 files, 9314 bytes uncompressed, 7113 bytes compressed:  23.6%

What I don't like is that the ./ is included in the zip archive generated by Python: how do I avoid this?

like image 550
LMGTFY Avatar asked Mar 11 '16 09:03

LMGTFY


1 Answers

Make sure that test is in an otherwise empty folder and zip that parent folder. shutil.make_archive() includes everything in the folder you designate, not the folder itself:

$ tree parent/
parent/
└── test
    ├── first.txt
    └── pof
        └── second.txt
$ bin/python
Python 2.7.11 (default, Feb 20 2016, 23:04:20)
[GCC 4.2.1 Compatible Apple LLVM 7.0.2 (clang-700.1.81)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import shutil
>>> shutil.make_archive('folder', 'zip', 'parent')
'/.../folder.zip'
>>> ^Z
$ zipinfo folder.zip
Archive:  folder.zip   504 bytes   5 files
drwxr-xr-x  2.0 unx        0 b- stor 11-Mar-16 11:19 ./
drwxr-xr-x  2.0 unx        0 b- stor 11-Mar-16 11:19 test/
drwxr-xr-x  2.0 unx        0 b- stor 11-Mar-16 11:19 test/pof/
-rw-r--r--  2.0 unx        0 b- defN 11-Mar-16 11:19 test/first.txt
-rw-r--r--  2.0 unx        0 b- defN 11-Mar-16 11:19 test/pof/second.txt
5 files, 0 bytes uncompressed, 4 bytes compressed:  0.0%

You can't prevent shutil.make_archive() from including the ./ current directory however. Write your own directory walking in that case:

import os
import os.path
import zipfile

zip_filename = 'folder.zip'
base_dir = os.path.abspath('parent')

with zipfile.ZipFile(zip_filename, "w",
                     compression=zipfile.ZIP_DEFLATED) as zf:
    base_path = os.path.normpath(base_dir)
    for dirpath, dirnames, filenames in os.walk(base_dir):
        for name in sorted(dirnames):
            path = os.path.normpath(os.path.join(dirpath, name))
            zf.write(path, os.path.relpath(path, base_path))
        for name in filenames:
            path = os.path.normpath(os.path.join(dirpath, name))
            if os.path.isfile(path):
                zf.write(path, os.path.relpath(path, base_path))
like image 104
Martijn Pieters Avatar answered Oct 08 '22 03:10

Martijn Pieters