Python: Zip all files individually in a folder - python

I have been trying to find out answer but nothing specific to my situation. I am very new to programming.
I have 20-30 .csv files in a folder.
I would like to loop through all files, and zip each csv file into .zip file (different folder)
C:\users\xyz\Source\NumberOne.csv
C:\users\xyz\Source\NumberTwo.csv
C:\users\xyz\Source\NumberThree.csv
C:\users\xyz\Dest\NumberOne.zip
C:\users\xyz\Dest\NumberTwo.zip
C:\users\xyz\Dest\NumberThree.zip
i have tried different code functions from internet, but nothing works on individual files. the working code i have, zips all files into 1 zip folder.
please help

This should work. You need to pass in the source and destination directories when running it (or modify the code).
import os
import sys
import zipfile
def csv_files(source_dir):
for filename in os.listdir(source_dir):
if filename.endswith('.csv'):
yield filename
source_dir = sys.argv[1] # r'C:\users\xyz\Source\'
dest_dir = sys.argv[2] # r'C:\users\xyz\Dest\'
os.chdir(source_dir) # To work around zipfile limitations
for csv_filename in csv_files(source_dir):
file_root = os.path.splitext(csv_filename)[0]
zip_file_name = file_root + '.zip'
zip_file_path = os.path.join(dest_dir, zip_file_name)
with zipfile.ZipFile(zip_file_path, mode='w') as zf:
zf.write(csv_filename)

To zip a file you can use this:
import commands
cmd = 'zip -j ' + zipfile + ' ' + file
commands.getstatusoutput(cmd)

To save all .csv files from a source folder as individual .zip archives in a destination folder:
#!/usr/bin/env python3
import sys
from pathlib import Path
from zipfile import ZipFile
src_dir, dest_dir = map(Path, sys.argv[1:])
for filename in src_dir.glob('*.csv'): # enumerate all csv-files in the src folder
# zip each file individually
with ZipFile(str(dest_dir / (filename.stem + '.zip')), 'w') as archive:
archive.write(str(filename), arcname=filename.name)
Example:
T:\> py zip-csv-files.py C:\users\xyz\Source C:\users\xyz\Dest

Related

zip folder's and take the name of folder

I'm trying to make this code which take the content of each folder in directory and add it to zip one by one with the name of folder
I did made this code but I'm blocked with just add file by extension in zip
import zipfile, os
handle = zipfile.ZipFile('ALL-PY.zip', 'w')
for x in os.listdir():
if x.endswith(directory):
handle.write(x,compress_type = zipfile.ZIP_DEFLATED)
handle.close()
I would follow this approach:
import zipfile, os
handle = zipfile.ZipFile('ALL-PY.zip', 'w')
path = "C:/Users/User_Name/my_directory" # This is YOUR INPUT - set with the directory you want to zip
os.chdir(path)
for directory, subs, files in os.walk("."):
handle.write(directory)
for this_file in files:
handle.write(os.path.join(directory, this_file), compress_type = zipfile.ZIP_DEFLATED)
handle.close()

How to move files with similar filename into new folder in Python

I have a list of files like this in the images folder.
and How can I create a new folder if there are multiple files with a similar name and move those similar files to that folder?
I am new to python.
Here is my expectation:
Try this:
import glob
from pathlib import Path
for fn in Path("Images").glob("*"):
file_base_name = "_".join(fn.stem.split("_")[:-1])
file_count = len(glob.glob1("Images", f"{file_base_name}*"))
if file_count > 1 or Path(file_base_name).is_dir():
outdir = Path("Images") / file_base_name
outdir.mkdir(exist_ok=True)
fn.rename(outdir / fn.name)
Input:
Output:
Please ignore file names extension. I create those just to test my code
In this case you don't even need re:
from pathlib import Path
for fn in Path("Images").glob("*.jpg"):
outdir = Path("Images") / "_".join(fn.stem.split("_")[:-1])
outdir.mkdir(exist_ok=True)
fn.rename(outdir / fn.name)
What's going on here?
Pathlib is how you want to think of paths if you can. It combines most of the os.path apis. Specifically:
glob gets us all the files matching the glob in the path
mkdir makes the directory (only if it doesn't exist)
rename moves the file there
I am unable to test since I don't have your files. My suggestion would be to comment out the mkdir command and the shutil.move command and replace them with print statements to see what commands would be generated before letting it run for real. But I think it should work.
import pathlib
import os
import re
from itertools import groupby
import shutil
source_dir = 'Images'
files = [os.path.basename(f) for f in pathlib.Path(source_dir).glob('*.jpg')]
def keyfunc(file):
m = re.match('^(.*?)_\d+.jpg$', file)
return m[1]
matched_files = [file for file in files if re.search(r'_\d+.jpg$', file)]
matched_files.sort()
for k, g in groupby(matched_files, keyfunc):
new_dir = os.path.join(source_dir, k)
if not os.path.exists(new_dir):
os.mkdir(new_dir)
for file in g:
shutil.move(os.path.join(source_dir, file), new_dir)

Create a zip of folders using zipfile

I have a folder called my_folder at the following Path /Users/my_user_name/Desktop/my_folder. The folder my_folder contains more folders like 323456, 987654 etc. Those folders contain some content. I want to create a zip of all those folders called myzip.zip such that when someone unzips it they see all those folders like 323456, 987654 at the root.
My Code
import os
from pathlib import Path
from zipfile import ZipFile
DOWNLOAD_DIR = Path("/Users/my_user_name/Desktop/my_folder")
ZIPPED_FILE_DIR = Path("/Users/my_user_name/Desktop/my_zip")
def get_list_of_all_folders(download_dir: Path):
return [f for f in download_dir.iterdir() if download_dir.is_dir()]
def zip_files():
folder_list = get_list_of_all_folders(DOWNLOAD_DIR)
with ZipFile(ZIPPED_FILE_DIR / "my_zip.zip", "w") as zip:
# writing each file one by one
for folder in folder_list:
zip.write(folder)
zip_files()
I have a function called get_list_of_all_folders where it goes to my_folder and gets a list of all the folders inside it that we want to zip. Then I use that folder_list to zip up each folder as part of my final zip called my_zip.zip. However there is something really wrong with my code and I am not sure what? The my_zip.zip is only 35 kb small when I know for a fact I am zipping up content over 2 gigabytes.
I looked at the zipfile document but did not find much help here as there are not many examples.
ZipFile.write expects to be supplied with the name of a file to write to the zip, not a folder.
You will need to iterate over the files in each folder and call write for each one. For example:
from pathlib import Path
from zipfile import ZipFile
DOWNLOAD_DIR = Path("/Users/my_user_name/Desktop/my_folder")
ZIPPED_FILE_DIR = Path("/Users/my_user_name/Desktop/my_zip")
def scan_dir(zip, dir, base_dir):
for f in dir.iterdir():
if f.is_dir():
scan_dir(zip, f, base_dir)
else:
# First param is the path to the file, second param is
# the path to use in the zip and when extracted. I just
# trim base_dir off the front.
zip.write(f, str(f)[len(str(base_dir)):])
def zip_files():
with ZipFile(ZIPPED_FILE_DIR / "my_zip.zip", "w") as zip:
for f in DOWNLOAD_DIR.iterdir():
scan_dir(zip, f, DOWNLOAD_DIR)
zip_files()
There's probably a neater way to trim off the base directory, but this was done quickly :)
You can use: shutil.make_archive
Below example taken from: https://docs.python.org/3/library/shutil.html#archiving-example
>>> import os
>>> from shutil import make_archive
>>> archive_name = os.path.expanduser(os.path.join('~', 'myarchive'))
>>> root_dir = os.path.expanduser(os.path.join('~', '.ssh'))
>>> make_archive(archive_name, 'zip', root_dir)
'/Users/tarek/myarchive.zip'
EDIT:
Code using ZipFile library
import zipfile
import os
class ZipUtilities:
def toZip(self, file, filename):
zip_file = zipfile.ZipFile(filename, 'w')
if os.path.isfile(file):
zip_file.write(file)
else:
self.addFolderToZip(zip_file, file)
zip_file.close()
def addFolderToZip(self, zip_file, folder):
for file in os.listdir(folder):
full_path = os.path.join(folder, file)
if os.path.isfile(full_path):
print('File added: ' + str(full_path))
zip_file.write(full_path)
elif os.path.isdir(full_path):
print('Entering folder: ' + str(full_path))
self.addFolderToZip(zip_file, full_path)
if __name__ == '__main__':
utilities = ZipUtilities()
filename = 'newfile.zip'
directory = 'foldername'
utilities.toZip(directory, filename)

Extracting zip with password to another dir without foldername

I have this password protected zip folder:
folder_1\1.zip
When I extract this it gives me
1\image.png
How can I extract this to another folder without its folder name? Just the contents of it: image.png
So far I have done all stackoverflows solutions and took me 11 hrs straight just to solve this.
import zipfile
zip = zipfile.ZipFile('C:\\Users\\Desktop\\folder_1\\1.zip', 'r')
zip.setpassword(b"virus")
zip.extractall('C:\\Users\\Desktop') <--target dir to extract all contents
zip.close()
EDIT:
This code worked for me: (Now I want many paths to be extracted at once, any ideas?
import os
import shutil
import zipfile
my_dir = r"C:\\Users\\Desktop"
my_zip = r"C:\\Users\\Desktop\\test\\folder_1\\1.zip"
with zipfile.ZipFile(my_zip) as zip_file:
zip_file.setpassword(b"virus")
for member in zip_file.namelist():
filename = os.path.basename(member)
# skip directories
if not filename:
continue
# copy file (taken from zipfile's extract)
source = zip_file.open(member)
target = file(os.path.join(my_dir, filename), "wb")
with source, target:
shutil.copyfileobj(source, target)
You can use the ZipFile.read() method to read the specific file in the archive, open your target file for writing by joining the target directory with the base name of the source file, and then write what you read to it:
import zipfile
import os
zip = zipfile.ZipFile('C:\\Users\\Desktop\\folder_1\\1.zip', 'r')
zip.setpassword(b"virus")
for name in zip.namelist():
if not name.endswith(('/', '\\')):
with open(os.path.join('C:\\Users\\Desktop', os.path.basename(name)), 'wb') as f:
f.write(zip.read(name))
zip.close()
And if you have several paths containing 1.zip for extraction:
import zipfile
import os
for path in 'C:\\Users\\Desktop\\folder_1', 'C:\\Users\\Desktop\\folder_2', 'C:\\Users\\Desktop\\folder_3':
zip = zipfile.ZipFile(os.path.join(path, '1.zip'), 'r')
zip.setpassword(b"virus")
for name in zip.namelist():
if not name.endswith(('/', '\\')):
with open(os.path.join('C:\\Users\\Desktop', os.path.basename(name)), 'wb') as f:
f.write(zip.read(name))
zip.close()

Extract files from zip without keeping the structure using python ZipFile?

I try to extract all files from .zip containing subfolders in one folder. I want all the files from subfolders extract in only one folder without keeping the original structure. At the moment, I extract all, move the files to a folder, then remove previous subfolders. The files with same names are overwrited.
Is it possible to do it before writing files?
Here is a structure for example:
my_zip/file1.txt
my_zip/dir1/file2.txt
my_zip/dir1/dir2/file3.txt
my_zip/dir3/file4.txt
At the end I whish this:
my_dir/file1.txt
my_dir/file2.txt
my_dir/file3.txt
my_dir/file4.txt
What can I add to this code ?
import zipfile
my_dir = "D:\\Download\\"
my_zip = "D:\\Download\\my_file.zip"
zip_file = zipfile.ZipFile(my_zip, 'r')
for files in zip_file.namelist():
zip_file.extract(files, my_dir)
zip_file.close()
if I rename files path from zip_file.namelist(), I have this error:
KeyError: "There is no item named 'file2.txt' in the archive"
This opens file handles of members of the zip archive, extracts the filename and copies it to a target file (that's how ZipFile.extract works, without taking care of subdirectories).
import os
import shutil
import zipfile
my_dir = r"D:\Download"
my_zip = r"D:\Download\my_file.zip"
with zipfile.ZipFile(my_zip) as zip_file:
for member in zip_file.namelist():
filename = os.path.basename(member)
# skip directories
if not filename:
continue
# copy file (taken from zipfile's extract)
source = zip_file.open(member)
target = open(os.path.join(my_dir, filename), "wb")
with source, target:
shutil.copyfileobj(source, target)
It is possible to iterate over the ZipFile.infolist(). On the returned ZipInfo objects you can then manipulate the filename to remove the directory part and finally extract it to a specified directory.
import zipfile
import os
my_dir = "D:\\Download\\"
my_zip = "D:\\Download\\my_file.zip"
with zipfile.ZipFile(my_zip) as zip:
for zip_info in zip.infolist():
if zip_info.filename[-1] == '/':
continue
zip_info.filename = os.path.basename(zip_info.filename)
zip.extract(zip_info, my_dir)
Just extract to bytes in memory,compute the filename, and write it there yourself,
instead of letting the library do it - -mostly, just use the "read()" instead of "extract()" method:
Python 3.6+ update(2020) - the same code from the original answer, but using pathlib.Path, which ease file-path manipulation and other operations (like "write_bytes")
from pathlib import Path
import zipfile
import os
my_dir = Path("D:\\Download\\")
my_zip = my_dir / "my_file.zip"
zip_file = zipfile.ZipFile(my_zip, 'r')
for files in zip_file.namelist():
data = zip_file.read(files, my_dir)
myfile_path = my_dir / Path(files.filename).name
myfile_path.write_bytes(data)
zip_file.close()
Original code in answer without pathlib:
import zipfile
import os
my_dir = "D:\\Download\\"
my_zip = "D:\\Download\\my_file.zip"
zip_file = zipfile.ZipFile(my_zip, 'r')
for files in zip_file.namelist():
data = zip_file.read(files, my_dir)
# I am almost shure zip represents directory separator
# char as "/" regardless of OS, but I don't have DOS or Windos here to test it
myfile_path = os.path.join(my_dir, files.split("/")[-1])
myfile = open(myfile_path, "wb")
myfile.write(data)
myfile.close()
zip_file.close()
A similar concept to the solution of Gerhard Götz, but adapted for extracting single files instead of the entire zip:
with ZipFile(zipPath, 'r') as zipObj:
zipInfo = zipObj.getinfo(path_in_zip))
zipInfo.filename = os.path.basename(destination)
zipObj.extract(zipInfo, os.path.dirname(os.path.realpath(destination)))
In case you are getting badZipFile error. you can unzip the archive using 7zip sub process. assuming you have installed the 7zip then use the following code.
import subprocess
my_dir = destFolder #destination folder
my_zip = destFolder + "/" + filename.zip #file you want to extract
ziploc = "C:/Program Files/7-Zip/7z.exe" #location where 7zip is installed
cmd = [ziploc, 'e',my_zip ,'-o'+ my_dir ,'*.txt' ,'-r' ]
#extracting only txt files and from all subdirectories
sp = subprocess.Popen(cmd, stderr=subprocess.STDOUT, stdout=subprocess.PIPE)

Categories