After copying files from a user provided source and destination, the files need to be renamed based on the creation time. The files have multiple extension types that need to be preserved while being renamed and a record original filenames. The issue arises when attempting to rename the file after it has been copied to the destination. All attempted solutions creates an exception in callback. What's the best approach here?
def filter_copy(self):
current_dir = self.Source.get()
destination_dir = self.Destination.get()
extensions = (['.avi', '.mpg'])
os.chdir(current_dir)
for root, dir, files in os.walk('.'):
for file in files:
if os.path.splitext(file)[1] in extensions:
src = os.path.join(root, file)
time.sleep(0.1)
logging.info("Copying the file %s..." % file)
print("Copying the file %s..." % file)
try:
with open('OriginalFilesReceipt.txt', 'w') as f:
f.write(file)
except FileNotFoundError:
logging.info("The directory does not exist to create to generate a receipt")
shutil.copy(src, destination_dir)
for names in os.listdir('.'):
t = os.path.getmtime(names)
v = datetime.datetime.fromtimestamp(t)
x = v.strftime('%Y%m%d-%H%M%S')
os.rename(names, x)
Found a solution based on the work from yzhong52 here: https://gist.github.com/tvdsluijs/1640613a32416b1197fc36b45e7b4999
The main error that was being received should have been obvious. The working directory wasn't the destination directory. The solution for the original question:
os.chdir(destination_dir)
for names in os.listdir('.'):
#split into filename and extension
filename, extension = os.path.splitext(names)
if (extension in extensions):
create_time = os.path.getctime(names)
format_time = datetime.datetime.fromtimestamp(create_time)
format_time_string = format_time.strftime("%Y-%m-%d %H.%M.%S")
newfile = format_time_string + extension
#if other file with same timestamp
if(newfile in newfilesDictionary.keys()):
index = newfilesDictionary[newfile] + 1
newfilesDictionary[newfile] = index
newfile = format_time_string + '-' + str(index) + extension
else:
newfilesDictionary[newfile] = 0
os.rename(names, newfile)
num_files = num_files + 1
print(names.rjust(35) + ' => ' + newfile.ljust(35))
I don't understand why I cannot extract file and why Python print KeyError: There is no item named eurofxref.zip in the archive lang interpreter see file as eurofxref.csv
import os
import zipfile
from file_from_web_class import FileFromWeb
if __name__ == "__main__":
url = "https://www.ecb.europa.eu/stats/eurofxref/eurofxref.zip"
dir = point_file_from_cwd("temp", "eurofxref.zip")
with FileFromWeb(url, dir) as f:
with zipfile.ZipFile(f.temp_file, "r") as z:
path = point_from_cwd("temp")
a_file = z.namelist()[0]
print(a_file) #? eurofxref.csv
os.chdir(path)
z.extract("eurofxref.zip", '.', None) #? I don't understand.
More details:
import os
import zipfile
import requests
class FileFromWeb:
def __init__(self, url, temp_file):
self.url = url
self.temp_file = temp_file
def __enter__(self):
response = requests.get(self.url)
with open(self.temp_file, "wb") as reading_file:
reading_file.write(response.content)
return self
def __exit__(self, exc_type, exc_val, exc_tb):
pass
Method on main.py file:
def point_from_cwd(rel_path):
defined_path = os.getcwd() + "\\" + rel_path
print("You want point dir: ", os.getcwd() + "\\" + rel_path)
return defined_path
def point_file_from_cwd(rel_path, file_name):
defined_path = os.getcwd() + "\\" + rel_path + "\\" + file_name
print("You want point file in dir: ", os.getcwd() + "\\" + rel_path + "\\" + file_name)
return defined_path
KeyError is a self-explanatory exception and it basically says "there is no item named eurofxref.zip in the archive" so probably you are trying to extract eurofxref.csv but providing wrong item.
It should be fine when you change this line if I understand your question with given details:
z.extract("eurofxref.zip", '.', None) #? I don't understand.
as:
z.extract("eurofxref.csv", '.', None) #? I don't understand.
ZipFile.extract extracts only specified member from the archive. Try:
z.extract("eurofxref.csv", '.', None)
or:
z.extractall()
I'm coding a script that either zips the hall folder or you can choose files with specific extension such as ".txt". I use sys.argv to pass the folder path and extension, if needed. However, when I pass the path the only thing I get is this error:
fileEx = sys.argv[2]
IndexError: list index out of range
How can I make the "file extension" command line optional?
My script:
import zipfile, os, sys
if len(sys.argv) < 2:
folder_path = sys.argv[1]
fileEx = None
else:
folder_path = sys.argv[1]
fileEx = sys.argv[2]
def zipf(folder_path, fileEx=None):
folder_path = os.path.abspath(folder_path)
number = 1
while True:
zipfilename= os.path.basename(folder_path) + "_" + str(number) +'.zip'
if not os.path.exists(zipfilename):
break
number = number + 1
# creat the zip file
print(f'creating {zipfilename}')
backupZip = zipfile.ZipFile(zipfilename, 'w')
# walking through folders
for foldername , subfolders , filenames in os.walk(folder_path):
print(f'Adding files in {foldername}. . . ')
#adding the folder
backupZip.write(foldername)
# adding all files in the folder to zipfile
for filename in filenames:
newBase = os.path.basename(folder_path) + '_'
if filename.startswith(newBase) and filename.endswith('.zip'):
continue
if fileEx:
if filename.endswith(fileEx):
os.chdir(foldername)
backupZip.write(os.path.join(foldername, filename))
else:
backupZip.write(os.path.join(foldername, filename))
backupZip.close()
zipf("folder_path, fileEx")
With pyminizip i am able to zip a file with password in python :
filepath=r"C:\Users\xxx\Desktop\myFolder\file.txt"
import pyminizip
pyminizip.compress(filepath, None,"output.zip", "password", 0)
But how do I zip the whole folder 'myFolder' into a zip file with password?
I tried removing the filename from the path but it gives the error
OSError: error in opening C:\Users\xxx\Desktop\myFolder for reading
EDIT :
The below link has a function which will zip the directory. But It wont add a password.
https://www.calazan.com/how-to-zip-an-entire-directory-with-python/
If anyone can let me know if it is possible to add a password to an existing zip file, that will solve my problem. Is that possible?
I was finally able to accomplish encryping the whole directory(including all subfolder struncture and files) using a library called 'pyzipper' suggested by Anupam Chaplot.
Here is the solution :
def zip_folderPyzipper(folder_path, output_path):
"""Zip the contents of an entire folder (with that folder included
in the archive). Empty subfolders will be included in the archive
as well.
"""
parent_folder = os.path.dirname(folder_path)
# Retrieve the paths of the folder contents.
contents = os.walk(folder_path)
try:
zip_file = pyzipper.AESZipFile('new_test.zip','w',compression=pyzipper.ZIP_DEFLATED,encryption=pyzipper.WZ_AES)
zip_file.pwd=b'PASSWORD'
for root, folders, files in contents:
# Include all subfolders, including empty ones.
for folder_name in folders:
absolute_path = os.path.join(root, folder_name)
relative_path = absolute_path.replace(parent_folder + '\\',
'')
print ("Adding '%s' to archive." % absolute_path)
zip_file.write(absolute_path, relative_path)
for file_name in files:
absolute_path = os.path.join(root, file_name)
relative_path = absolute_path.replace(parent_folder + '\\',
'')
print ("Adding '%s' to archive." % absolute_path)
zip_file.write(absolute_path, relative_path)
print ("'%s' created successfully." % output_path)
except IOError as message:
print (message)
sys.exit(1)
except OSError as message:
print(message)
sys.exit(1)
except zipfile.BadZipfile as message:
print (message)
sys.exit(1)
finally:
zip_file.close()
Since I am new in python i cant explain the code in detail. Here are the references :
https://pypi.org/project/pyzipper/
https://www.calazan.com/how-to-zip-an-entire-directory-with-python/
To extract the Generated ZIP file in windows :
Right Click - > Unzip(Encripted)
If you directly click Extract All option, then it will give error
Try this:
Firstly check here please for pynzip. After that try it.
import pyminizip as pyzip
compression = 8
pyzip.compress("test.txt", "test.zip", "Pswrd", compression)
Here is how to copy all a directory with its subdirectories and its files, then compress it and encrypt a zip, with password and without needing an associated backup file, here we will see how to authorize a mac address to execute the decryption. So then it's up to you to change or improve the script.
But the essentials work very well.
After a lot of research, testing and thinking, I created this effective solution
my setup:
Python 3.8 64:bits on windows 7 64:bits
Usage terminology:
First step, we need to import the cryptography module
check for support or other is here https://cryptography.io/en/latest/installation/
command:
pip install cryptography
Then we will use the fernet object resulting from this module
https://cryptography.io/en/latest/fernet/
with password
https://cryptography.io/en/latest/fernet/#using-passwords-with-fernet
and shutil:
https://docs.python.org/3/library/shutil.html
file second.py:
import os
import re, uuid
import string
import shutil
import zlib
from cryptography.fernet import Fernet
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
import base64
import zipfile
class zipy:
def __init__(self, pathDir=None):
"""If pathDir optional is none, this script copy all directory in current execution."""
if pathDir != None:
if os.path.isdir(pathDir):
pathDir = pathDir.replace(os.sep, '/')
if pathDir.endswith('/'):
self.root = pathDir
else:
self.root = pathDir + '/'
else:
self.root = os.getcwd()+os.sep
self.root = self.root.replace(os.sep, '/')
else:
self.root = os.getcwd()+os.sep
self.root = self.root.replace(os.sep, '/')
os.chdir(self.root)
self.name = 'sauvegarde'
self.dirSauvegarde = self.root+self.name
self.dirSauvegarde = self.dirSauvegarde.replace(os.sep, '/')
lectureDossier = os.listdir(self.root)
print(lectureDossier)
self.path_system = {}
for element in lectureDossier:
if os.path.isdir(element):
if element != '__pycache__':
self.path_system[element] = self.root + element + os.sep.replace(os.sep, '/')
self.path_system[element] = self.path_system[element].replace(os.sep, '/')
else:
pass
elif os.path.isfile(element):
self.path_system[element] = self.root + element
self.path_system[element] = self.path_system[element].replace(os.sep, '/')
else:
pass
self.zipi = myZip(self.dirSauvegarde)
def save(self):
"""sauvegarde le fichier"""
self.createDir(self.dirSauvegarde)
chemin_src = ""
chemin_dist = ""
for element in self.path_system:
if element != self.dirSauvegarde:
chemin_src = self.root+element
chemin_dest = self.dirSauvegarde + os.sep + element
chemin_dest = chemin_dest.replace(os.sep, '/')
if os.path.isdir(chemin_src):
self.copyDir(chemin_src, chemin_dest)
else:
self.copyFile(chemin_src, chemin_dest)
self.zipi.zip(zip_exist=True)
self.delDir(self.dirSauvegarde)
def copyDir(self, src, dest):
try:
shutil.copytree(src, dest, dirs_exist_ok=True)
except:
pass
def copyFile(self, src, dest):
try:
shutil.copyfile(src, dest)
except:
pass
def createDir(self, dirPath):
if os.path.isdir(dirPath):
self.delDir(dirPath)
else:
pass
os.makedirs(dirPath, exist_ok=True)
def delDir(self, dir):
if os.path.isdir(dir):
if len(os.listdir(dir)) > 0:
try:
print('rmtree')
shutil.rmtree(dir, ignore_errors=True)
except:
pass
else:
try:
os.rmdir(dir)
except:
pass
def decrypt(self):
self.zipi.unzip()
class myZip:
def __init__(self, dir):
self.pathDir = dir
self.nom = os.path.basename(dir)
self.pathZip = self.pathDir + '.zip'
self.crypt = Encryptor()
def zip(self, zip_exist=False):
if zip_exist == False:
pass
else:
if os.path.isfile(self.pathZip):
try:
os.remove(self.pathZip)
except:
pass
shutil.make_archive(os.path.splitext(self.pathZip)[0], 'zip', self.pathDir)
key = self.crypt.key_create()
#TEST
self.crypt.file_encrypt(key, self.pathZip, self.pathZip)
self.crypt.key_write(self.pathZip, key)
def unzip(self):
#TEST
if self.crypt.checkPass(self.pathZip):
#print('ok adresse mac autoriser')
key = self.crypt.key_load(self.pathZip)
self.crypt.file_decrypt(key, self.pathZip, self.pathZip)
else:
print('pas ok adresse mac erroner')
class Encryptor:
def __init__(self):
self.salto = None
def key_create(self):
password = self.getMac()
password = bytes(password, encoding="utf-8")
self.salto = os.urandom(16)
print(self.salto)
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32,
salt=self.salto,
iterations=100,
)
key = base64.urlsafe_b64encode(kdf.derive(password))
return key
def key_write(self, pathZip, key):
with zipfile.ZipFile(pathZip, 'a') as zip:
zip.comment = key + bytes(' byMe ', encoding="utf-8") + self.salto
def key_load(self, pathZip):
stri = []
with zipfile.ZipFile(pathZip, 'a') as zip:
stri = zip.comment.split(b' byMe ')
print(stri[0])
print(stri[1])
key = stri[0]
self.salto = stri[1]
return key
def checkPass(self, pathZip):
key = base64.urlsafe_b64decode(self.key_load(pathZip))
salt = self.salto
mdp = self.getMac()
mdp = bytes(mdp, encoding="utf-8")
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32,
salt=salt,
iterations=100,
)
retour = False
try:
kdf.verify(mdp, key)
retour = True
except:
retour = False
return retour
def file_encrypt(self, key, original_file, encrypted_file):
f = Fernet(key)
with open(original_file, 'rb') as file:
original = file.read()
encrypted = f.encrypt(original)
with open (encrypted_file, 'wb') as file:
file.write(encrypted)
def file_decrypt(self, key, encrypted_file, decrypted_file):
f = Fernet(key)
with open(encrypted_file, 'rb') as file:
encrypted = file.read()
decrypted = f.decrypt(encrypted)
with open(decrypted_file, 'wb') as file:
file.write(decrypted)
def getMac(self):
return "".join(re.findall('..', '%012x' % uuid.getnode()))
Use like this:
file : main.py
from second import zipy
#If the argument is empty, the script will make a copy of the directory being executed, otherwise the script will work and output the zip in the place indicated in argument
dd = zipy("E:/path")
#or dd = zipy("E:/path/") or dd = zipy() if you give arg, give absolute path
#Save the zip and encrypt it. Change second.py to directly give it a password as an argument
dd.save()
#decrypt zip
dd.decrypt()
Here's a snippet with pyminizip: gets a list of files and zips the whole thing.
import pyminizip
import os
def get_paths_recursively(src_root_path):
files = []
if src_root_path is not None:
for root, directories, filenames in os.walk(src_root_path):
entries = []
for filename in filenames:
full_file_name = os.path.join(root, filename)
if os.path.isfile(full_file_name) and not filename.startswith('.'):
files.append(os.path.join(root, filename))
return files
def pyminizip_zipper(folder_path, output_path, password):
paths = get_paths_recursively(folder_path)
roots = []
for path in paths:
roots.append(os.path.dirname(path.replace(os.path.dirname(folder_path), './')))
pyminizip.compress_multiple(paths, roots, output_path, password, 5)
I have a folder with a list of files without extensions, I need to rename or create an extension to each file ".text"
This is my code, but there is a small bug, the second time I run the code the files renamed again with a long name ,, for example
The file name : XXA
after first run : XXA.text
second : XXAXXA.text.text
import os
def renamefiles():
filelist = os.listdir(r"D:\")
print(filelist)
os.chdir(r"D:\")
path = os.getcwd()
for filename in filelist:
print("Old Name - "+filename)
(prefix, sep, sffix) = filename.rpartition(".")
newfile = prefix + filename + '.text'
os.rename(filename, newfile)
print("New Name - "+newfile)
os.chdir(path)
rename_files()
Where you have
newfile = prefix + '.text'
You can have
if not file_name.contains(".text"):
newfile = prefix + file_name + '.text'
Note where you have newfile = prefix + file_name + '.text', I changed it to newfile = prefix + '.text'. If you think about it, you don't need filename when you have already extracted the actual file name into prefix.
for file in os.listdir(os.curdir):
name, ext = os.path.splitext(file)
os.rename(file, name + ".text")
Don't do the partitioning that way, use os.path.splitext:
file_name, extension = os.path.splitext(filename)
if not extension:
newfile = file_name + '.text'
os.rename(filename, newfile)
If the file has no extension splitext returns '' which is Falsy. The file extension can then be changed.
import os
def renamefiles():
filelist = os.listdir(r"D:\")
print(filelist)
os.chdir(r"D:\")
path = os.getcwd()
for filename in filelist:
print("Old Name - "+filename)
(prefix, sep, sffix) = filename.rpartition(".")
newfile = prefix + filename + '.text'
if not filename.endswith(".text"):
os.rename(filename, newfile)
print("New Name - "+newfile)
os.chdir(path)
renamefiles()
You need to check if the filename ends with .text, and skip those