Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python How to copy files inside a zip to another zip in memory?

Tags:

python

zip

Purpose

Split a zip archive into smaller zip archives with an evenly distributed # of files per new zip.

Example

source zip (100 files)

  • src/100-Test.zip

destination zips (25 files each):

  • destination/1.zip
  • destination/2.zip
  • destination/3.zip
  • destination/4.zip

Description

So I have been able to open the zip file and iterate through the contents to split them up, but I have not been able to write to the file. Since I didn't do anything with the zip contents I didn't think I had to do any StringIO stuff or anything?

Code

zipFileNameSrc = '100-Test.zip'
zipFile = open(zipFileNameSrc)
unzippedFile = zipfile.ZipFile(zipFile)
imgList = [(s, unzippedFile.read(s)) for s in unzippedFile.namelist() if (".jpg" or ".JPG") in s]
#image names: imgList[i][0]  and  images: imgList[i][1]

#...
#...additional logic to split into sets of 25 images
#...fileTuplesList = imgList[:25]
zipNo = 1
#zipFileDest = destination + "/" + zipSrcNm + "/" + zipNo.__str__() + ".zip"
zipFileName = zipNo.__str__() + ".zip"
zipOut = zipfile.ZipFile(zipFileName, 'w')
for i in xrange(len(fileTuplesList)):
    fileNameAndPath = fileTuplesList[i][0]
    actualFile = fileTuplesList[i][1]
    zipOut.write(fileNameAndPath, actualFile)
zipOut.close()
#move_files(zipFileName, zipFileDest)

Error

I get on this on line zipOut.write(fileNameAndPath, actualFile)

OSError: [Errno 2] No such file or directory: '100-Test/17.jpg'

Bonus

How to save the zip file to a different folder than where my script is?

like image 364
alfredox Avatar asked Oct 20 '22 05:10

alfredox


1 Answers

ZipFile.write() expects a filename as first argument, and that file should exist in the system. If it does, that particular file is copied into the zip archive.

You actually want to use - ZipFile.writestr() - it expects the archivename as first argument and data as the second argument.

Also, you can create your zip archives anywhere, just use os.path.join() to join the directory to zip file name when creating the zipFileName . Example code that does what you want -

import os.path
zipFileNameSrc = '100-Test.zip'
zipFile = open(zipFileNameSrc)
unzippedFile = zipfile.ZipFile(zipFile)
imgList = [(s, unzippedFile.read(s)) for s in unzippedFile.namelist() if (".jpg" or ".JPG") in s]
#image names: imgList[i][0]  and  images: imgList[i][1]

#...
#...additional logic to split into sets of 25 images
#...fileTuplesList = imgList[:25]
zipNo = 1
#zipFileDest = destination + "/" + zipSrcNm + "/" + zipNo.__str__() + ".zip"
zipFileName = os.path.join('<directory for zip>',zipNo.__str__() + ".zip")
zipOut = zipfile.ZipFile(zipFileName, 'w')
for i in xrange(len(fileTuplesList)):
    fileNameAndPath = fileTuplesList[i][0]
    actualFile = fileTuplesList[i][1]
    zipOut.writestr(fileNameAndPath, actualFile)
zipOut.close()

Example/Demo code that worked in my system -

import zipfile
import os.path
zipFileNameSrc = 'ziptest.zip'
zipFile = open(zipFileNameSrc, 'rb')
unzippedFile = zipfile.ZipFile(zipFile)
imgList = [(s, unzippedFile.read(s)) for s in unzippedFile.namelist() if (".png" or ".PNG")]
for i in range(1,5):
    zipFileName = os.path.join('<some location>','ziptest_' + str(i) + '.zip')
    print('Creating ', zipFileName)
    zipOut = zipfile.ZipFile(zipFileName, 'w')
    for j in range(25):
        ind = (i-1)*25 + j
        fileNameAndPath = imgList[ind][0]
        actualFile = imgList[ind][1]
        zipOut.writestr(fileNameAndPath, actualFile)
    zipOut.close()
like image 90
Anand S Kumar Avatar answered Oct 22 '22 00:10

Anand S Kumar