Having a small issues when trying to create a zip file using the zipfile module in python 3.
I have a directory which contains xml files, I am looking to create a zip archive from all these files in the same directory but keep encountering the error of FileNotFoundError: [Errno 2] no such file or directory: 'file.xml'
script:
import datetime
import os
import zipfile
path = '/Users/xxxx/reports/xxxx/monthly'
month = datetime.datetime.now().strftime('%G'+'-'+'%B')
zf = os.path.join(path, '{}.zip'.format(month))
z = zipfile.ZipFile(zf, 'w')
for i in os.listdir(path):
if i.endswith('.xml'):
z.write(i)
z.close()
it seems like when z.write(i) is called it is looking in the working directory for the xml files however the working directory is /Users/xxxx/scripts where the python script is.
How would I get the z.write(i) to look at the path variable without changing the current working directory if possible.
What actually happens is that as you loop through os.listdir(path), the i itself is simply the FileName which does not include the real Path to the File. There are a couple of ways to get around this; the simplest (but crudest) of which is shown below:
import datetime
import os
import zipfile
path = '/Users/xxxx/reports/xxxx/monthly'
month = datetime.datetime.now().strftime('%G'+'-'+'%B')
zf = os.path.join(path, '{}.zip'.format(month))
z = zipfile.ZipFile(zf, 'w')
for i in os.listdir(path):
# DECLARE A VARIABLE TO HOLD THE FULL PATH TO THE FILE:
xmlFile = "{}/{}".format(path, i) # <== PATH TO CURRENT FILE UNDER CURSOR
if xmlFile.endswith('.xml'):
z.write(xmlFile)
z.write(filename=xmlFile, arcname="ARCHIVE_NAME_HERE", ) # <== CHANGE
z.close()
Hope this Helps.
Cheers and Good-Luck...
use os.chdir to move to the file path and try to write the files to zip.
import datetime
import os
import zipfile
path = '/Users/xxxx/reports/xxxx/monthly'
month = datetime.datetime.now().strftime('%G'+'-'+'%B')
zf = os.path.join(path, '{}.zip'.format(month))
z = zipfile.ZipFile(zf, 'w')
os.chdir(path) #Change DIR
for i in os.listdir(path):
if i.endswith('.xml'):
z.write(i)
z.close()
Without changing DIR:
z = zipfile.ZipFile(zf, 'w')
for i in os.listdir(path):
if i.endswith('.xml'):
z.write(os.path.join(path, i))
z.close()
Related
you will find my code i am not python pro but i do everything to become it
import os, sys
os.listdir(os.getcwd())
Out[3]: ['.ipynb_checkpoints',
'helmet_10_0.png',
'helmet_10_1.png',
'helmet_10_10.png',
I wish
Out[0]: ['casque_Chantier_10_0.png',
'casque_Chantier_10_10.png',
'casque_Chantier_10_100.png'
so on
source = 'D:\\Chasse_Au_tressor\\base_agmt\\extractedFrames_step_5\\helmet_10_0.png'
dest = 'D:\\Chasse_Au_tressor\\base_agmt\\extractedFrames_step_5\\Casque_Chantier_10_0.png'
os.rename(source, dest)
Out[2]: ['casque_Chantier_10_0.png',
'helmet_10_1.png',
'helmet_10_10.png',
'helmet_10_100.png',
'helmet_10_101.png',
I can't make a loop which takes all the files with 'glob' and renames them
<ipython-input-33-1a271eebe4a0> in <module>
1 for i in source:
2 if i != dest:
----> 3 os.rename(i,dest)
FileNotFoundError: [WinError 2] Le fichier spécifié est introuvable: 'D' -> 'D:\\Chasse_Au_tressor\\base_agmt\\extractedFrames_step_5\\Casque_Chantier_{*}.png'
I want the images on casque_Chantier_{index=1}.png
Try this. You can just rename the file name instead of opening it and renaming it once again which will save memory while performing the action on multiple files in a for loop. This will also make sure that only the intended files i.e. file names which start with "helmet" alone are renamed
#Import package
import os
#Loop through the file names
for filename in os.listdir(os.getcwd()):
if filename.startswith("helmet_"):
os.rename(filename, "casque_Chantier_"+filename[7:])
Cheers!
The following code iterates through each file and renames the file as required. It replaces the "helmet_" part with "casque_Chantier_".
I have set this up so that it runs in the same folder as the files to be renamed.
import os
for file in os.listdir():
os.rename(file, file.replace("helmet_","casque_Chantier_")
import os, sys
directory = os.getcwd()
filenames = os.listdir(directory)
renamed_filenames = [f.replace('helmet', 'casque_Chantier') for f in filenames]
for i in range(len(filenames)):
source_filepath = os.path.join(directory, filenames[i])
dest_filepath = os.path.join(directory, renamed_filenames[i])
os.rename(source_filepath, dest_filepath)
The following works for python 3.6
You will need replace from string library to change 'helmet' into 'casque_Chantier' :
import shutil
import os
dir_path = os.getcwd()
for filename in os.listdir(dir_path):
src = os.path.join(dir_path, filename)
dst = os.path.join(dir_path, filename.replace("helmet", "casque_Chantier"))
shutil.move(src, dst)
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()
I'm attempting to remove a zipped file after unzipping the contents on windows. The contents can be stored in a folder structure in the zip. I'm using the with statement and thought this would close the file-like object (source var) and zip file. I've removed lines of code relating to saving the source file.
import zipfile
import os
zipped_file = r'D:\test.zip'
with zipfile.ZipFile(zipped_file) as zip_file:
for member in zip_file.namelist():
filename = os.path.basename(member)
if not filename:
continue
source = zip_file.open(member)
os.remove(zipped_file)
The error returned is:
WindowsError: [Error 32] The process cannot access the file because it is being used by another process: 'D:\\test.zip'
I've tried:
looping over the os.remove line in case it's a slight timing issue
Using close explicitly instead of the with statment
Attempted on local C drive and mapped D Drive
instead of passing in a string to the ZipFile constructor, you can pass it a file like object:
import zipfile
import os
zipped_file = r'D:\test.zip'
with open(zipped_file, mode="r") as file:
zip_file = zipfile.ZipFile(file)
for member in zip_file.namelist():
filename = os.path.basename(member)
if not filename:
continue
source = zip_file.open(member)
os.remove(zipped_file)
You are opening files inside the zip... which create a file lock on the whole zip file. close the inner file open first... via source.close() at the end of your loop
import zipfile
import os
zipped_file = r'D:\test.zip'
with zipfile.ZipFile(zipped_file) as zip_file:
for member in zip_file.namelist():
filename = os.path.basename(member)
if not filename:
continue
source = zip_file.open(member)
source.close()
os.remove(zipped_file)
Try to close the zipfile before removing.
you can do also like this, which works pretty good:
import os, shutil, zipfile
fpath= 'C:/Users/dest_folder'
path = os.getcwd()
for file in os.listdir(path):
if file.endswith(".zip"):
dirs = os.path.join(path, file)
if os.path.exists(fpath):
shutil.rmtree(fpath)
_ = os.mkdir(fpath)
with open(dirs, 'rb') as fileobj:
z = zipfile.ZipFile(fileobj)
z.extractall(fpath)
z.close()
os.remove(dirs)
I have the below to zip a file. the file zips correctly, but contains the folders within the zip. How can I just zip the file, whilst still being able to show where the file is located?
create_zip_path = "folder1\\folder2\\my_zip.zip"
file_to_add_to_zip = "folder1\\folder2\\my_file.txt"
zip_file(create_zip_path, file_to_add_to_zip)
def zip_file(create_zip_path, file_to_add_to_zip):
import zipfile
try:
import zlib
compression = zipfile.ZIP_DEFLATED
except:
compression = zipfile.ZIP_STORED
modes = { zipfile.ZIP_DEFLATED: 'deflated',
zipfile.ZIP_STORED: 'stored',
}
zf = zipfile.ZipFile(create_zip_path, mode='w')
zf.write(file_to_add_to_zip, compress_type=compression)
You can use the os module to change your working directory. This should work:
import os
print os.getcwd() #Your current working directory
os.chdir(os.getcwd() + '/folder1/folder2/')
print os.getcwd() #Your new wordking dir
create_zip_path = "my_zip.zip"
file_to_add_to_zip = "my_file.txt"
zip_file(create_zip_path, file_to_add_to_zip)
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)