zip file and avoid directory structure

Solution 1:

The zipfile.write() method takes an optional arcname argument that specifies what the name of the file should be inside the zipfile

I think you need to do a modification for the destination, otherwise it will duplicate the directory. Use :arcname to avoid it. try like this:

import os
import zipfile

def zip(src, dst):
    zf = zipfile.ZipFile("%s.zip" % (dst), "w", zipfile.ZIP_DEFLATED)
    abs_src = os.path.abspath(src)
    for dirname, subdirs, files in os.walk(src):
        for filename in files:
            absname = os.path.abspath(os.path.join(dirname, filename))
            arcname = absname[len(abs_src) + 1:]
            print 'zipping %s as %s' % (os.path.join(dirname, filename),
                                        arcname)
            zf.write(absname, arcname)
    zf.close()

zip("src", "dst")

Solution 2:

zf.write(tofile)

to change

zf.write(tofile, zipfile_dir)

for example

zf.write("/root/files/result/root/files/result/new.txt", "/root/files/results/new.txt")

Solution 3:

To illustrate most clearly,

directory structure:

/Users
 └── /user
 .    ├── /pixmaps
 .    │    ├── pixmap_00.raw
 .    │    ├── pixmap_01.raw
      │    ├── /jpeg
      │    │    ├── pixmap_00.jpg
      │    │    └── pixmap_01.jpg
      │    └── /png
      │         ├── pixmap_00.png
      │         └── pixmap_01.png
      ├── /docs
      ├── /programs
      ├── /misc
      .
      .
      .

Directory of interest: /Users/user/pixmaps

First attemp

import os
import zipfile

TARGET_DIRECTORY = "/Users/user/pixmaps"
ZIPFILE_NAME = "CompressedDir.zip"

def zip_dir(directory, zipname):
    """
    Compress a directory (ZIP file).
    """
    if os.path.exists(directory):
        outZipFile = zipfile.ZipFile(zipname, 'w', zipfile.ZIP_DEFLATED)

        for dirpath, dirnames, filenames in os.walk(directory):
            for filename in filenames:

                filepath   = os.path.join(dirpath, filename)
                outZipFile.write(filepath)

        outZipFile.close()




if __name__ == '__main__':
    zip_dir(TARGET_DIRECTORY, ZIPFILE_NAME)

ZIP file structure:

CompressedDir.zip
.
└── /Users
     └── /user
          └── /pixmaps
               ├── pixmap_00.raw
               ├── pixmap_01.raw
               ├── /jpeg
               │    ├── pixmap_00.jpg
               │    └── pixmap_01.jpg
               └── /png
                    ├── pixmap_00.png
                    └── pixmap_01.png

Avoiding the full directory path

def zip_dir(directory, zipname):
    """
    Compress a directory (ZIP file).
    """
    if os.path.exists(directory):
        outZipFile = zipfile.ZipFile(zipname, 'w', zipfile.ZIP_DEFLATED)

        # The root directory within the ZIP file.
        rootdir = os.path.basename(directory)

        for dirpath, dirnames, filenames in os.walk(directory):
            for filename in filenames:

                # Write the file named filename to the archive,
                # giving it the archive name 'arcname'.
                filepath   = os.path.join(dirpath, filename)
                parentpath = os.path.relpath(filepath, directory)
                arcname    = os.path.join(rootdir, parentpath)

                outZipFile.write(filepath, arcname)

    outZipFile.close()




if __name__ == '__main__':
    zip_dir(TARGET_DIRECTORY, ZIPFILE_NAME)

ZIP file structure:

CompressedDir.zip
.
└── /pixmaps
     ├── pixmap_00.raw
     ├── pixmap_01.raw
     ├── /jpeg
     │    ├── pixmap_00.jpg
     │    └── pixmap_01.jpg
     └── /png
          ├── pixmap_00.png
          └── pixmap_01.png

Solution 4:

Check out the documentation for Zipfile.write.

ZipFile.write(filename[, arcname[, compress_type]]) Write the file named filename to the archive, giving it the archive name arcname (by default, this will be the same as filename, but without a drive letter and with leading path separators removed)

https://docs.python.org/2/library/zipfile.html#zipfile.ZipFile.write

Try the following:

import zipfile
import os
filename = 'foo.txt'

# Using os.path.join is better than using '/' it is OS agnostic
path = os.path.join(os.path.sep, 'tmp', 'bar', 'baz', filename)
zip_filename = os.path.splitext(filename)[0] + '.zip'
zip_path = os.path.join(os.path.dirname(path), zip_filename)

# If you need exception handling wrap this in a try/except block
with zipfile.ZipFile(zip_path, 'w') as zf:
    zf.write(path, zip_filename)

The bottom line is that if you do not supply an archive name then the filename is used as the archive name and it will contain the full path to the file.

Solution 5:

You can isolate just the file name of your sources files using:

name_file_only= name_full_path.split(os.sep)[-1]

For example, if name_full_path is /root/files/results/myfile.txt, then name_file_only will be myfile.txt. To zip myfile.txt to the root of the archive zf, you can then use:

zf.write(name_full_path, name_file_only)