Renaming all files in a folder with python using specific condition - python

I have a folder which has files with names:
"fileX.JPG" where X = 1....N
and I want to name the files as :
"000000000X.JPG" where X=1...N
The new name of the file should have the number from the old name of the file plus the zeros. so example file names I want is:
0000000000001.jpg
0000000000011.jpg
0000000000111.jpg
etc
The file name is 13 characters long. so should have zeros accordingly.
I have not started my code. Don't know where should I start.

You can use os.rename() from the os module

for path in pathlib.Path("a_directory").iterdir():
if path.is_file():
old_name = path.stem
#original filename
old_extension = path.suffix
#original file extension
Also try this:
import os
path = '/Users/myName/Desktop/directory'
files = os.listdir(path)
for index, file in enumerate(files):
os.rename(os.path.join(path, file), os.path.join(path, ''.join([str(index), '.jpg'])))
directory = path.parent
#current file location
new_name = "text" + old_name + old_extension
path.rename(pathlib.Path(directory, new_name))

You can use os.rename.
For example:
for file in os.listdir():
# Get the number, e.g.:
old_number = file.strip("file")[1].strip(".JPG")[0]
os.rename(file, f"{old_number}.JPG")
You might have to adapt based on how your files are actually namd

import os
# Function to rename multiple files
def main():
for count, filename in enumerate(os.listdir("path-to-files")):
d = str(count).zfill(12)
dst = d + ".jpg"
src ='path-to-file'+ filename
dst ='path-to-file'+ dst
# rename() function will
# rename all the files
os.rename(src, dst)
# Driver Code
if __name__ == '__main__':
# Calling main() function
main()

Related

How to zip files that ends with certain extension

I want to get all files in a directory (I reached it after doing several for loops - hence fourth.path) that ends with .npy or with csv and then zip those files.
My code is running putting one file only in the zip file. What am I doing wrong?
I tried to change my indents, but no zip file is being created
import json
import os
import zipfile
import zlib
directory = os.path.join(os.getcwd(), 'recs')
radarfolder = 'RadarIfxAvian'
file = os.listdir(directory)
def r(p, name):
p = os.path.join(p, name)
return p.replace("/", "\\")
#This code will list all json files in e ach file
for first in os.scandir(directory):
if first.is_dir():
for second in os.scandir(first.path):
if second.is_dir():
for third in os.scandir(second.path):
if third.is_dir():
radar_folder_name = ''
list_files = ()
for fourth in os.scandir(third.path):
if fourth.is_dir():
if radarfolder in fourth.path:
radar_folder_name = fourth.path
print(radar_folder_name)
list_files = ()
for file in os.listdir(fourth.path):
if file.endswith(".npy") | file.endswith(".csv"):
list_files = (file)
print(list_files)
with zipfile.ZipFile(radar_folder_name +'\\' +'radar.zip', 'w', compression=zipfile.ZIP_DEFLATED ) as zipMe:
zipMe.write(radar_folder_name +'\\' +list_files)
zipMe.close()
I tried to change my indents either resulting in error: TypeError: can only concatenate str (not "tuple") to str or no zip file being created
As I said in my second comment, your problem comes from the 'w' argument in your zipping statement. It causes the zip to be overwritten every time it's opened, which you do for each file you zip in. You can fix this 2 ways (at least):
Replace 'w' with 'a'; this way the files will be appended to your zip (with the side effect that, if you do this several times, files will be added more than once).
Keep the 'w', but only open the zip once, having listed all the files you want to zip before. See my code below.
I've taken the liberty to rewrite the part of your code where you look for the 'RadarIfxAvian' folder, since embedded for are clumsy (and if your folder structure changes, they might not work), replacing it with a multi-purpose recursive function.
Note that the folder structure will be included in the .zip; if you want to zip only the files themselves, consider doing os.chdir(radar_folder_name) before zipping the files.
# This function recursively looks for the 'filename' file or folder
# under 'start_path' and returns the full path, or an empty string if not found.
def find_file(start_path, filename):
if filename in os.listdir(start_path):
return start_path + '/' + filename
for file in os.scandir(start_path):
if not file.is_dir():
continue
if (deep_path:=find_file(start_path + '/' + file.name, filename)):
return deep_path
return ''
directory = os.path.join(os.getcwd(), 'recs')
radarfolder = 'RadarIfxAvian'
radar_folder_name = find_file(directory, radarfolder)
print(radar_folder_name)
list_files = []
for file in os.listdir(radar_folder_name):
if file.endswith(".npy") or file.endswith(".csv"):
list_files.append(file)
with zipfile.ZipFile(radar_folder_name + '/' + 'radar.zip', 'w', compression=zipfile.ZIP_DEFLATED ) as zipMe:
for file in list_files:
zipMe.write(radar_folder_name + '/' + file)
If I understand your code correctly, you are looking for a folder "RadarIfxAvian" and want to place a .ZIP in that folder containing any .CSV or .NPY files in that directory. This should do the equivalent, using os.walk for the recursive search:
import os
import zipfile
for path, dirs, files in os.walk('recs'):
if os.path.basename(path) == 'RadarIfxAvian':
print(path)
with zipfile.ZipFile(os.path.join(path, 'radar.zip'), 'w', zipfile.ZIP_DEFLATED) as zip:
for file in files:
if file.endswith(".npy") | file.endswith(".csv"):
print(file)
zip.write(file)
break # stop search once the directory is found and processed
I adjusted my code with the following steps:
Put the if in a function
writing the the zip by looping over each item in the list I appended
import json
import os
import glob
import zipfile
import zlib
directory = os.path.join(os.getcwd(), 'recs')
radarfolder = 'RadarIfxAvian'
file = os.listdir(directory)
list_files = []
def r(p, name):
p = os.path.join(p, name)
return p.replace("/", "\\")
def tozip(path, file):
filestozip = []
if file.endswith(".npy") or file.endswith(".csv"):
filestozip = (path + '\\' + file)
list_files.append(filestozip)
return list_files
#This code will list all json files in each file
for first in os.scandir(directory):
if first.is_dir():
for second in os.scandir(first.path):
if second.is_dir():
for third in os.scandir(second.path):
if third.is_dir():
radar_folder_name = ''
filestozip = []
list_files.clear()
for fourth in os.scandir(third.path):
if fourth.is_dir():
if radarfolder in fourth.path:
radar_folder_name = fourth.path
for file in os.listdir(fourth.path):
filestozip = tozip(radar_folder_name,file)
print(filestozip)
ZipFile = zipfile.ZipFile(r(radar_folder_name,"radar.zip"), "w")
for a in filestozip:
ZipFile.write(a, compress_type= zipfile.ZIP_DEFLATED)
print(radar_folder_name + "added to zip")

Rename multiple files by removing filename prefix

I'm new to Python, I have multiple files in a folder where I need to rename those files as the the given pattern.
Example:
Folder : /Users/Usr1/Documents/FilesFolder and
File's :
0. a101.employee.txt
1. a101.department.txt
2. a101.salary.txt
I want to remove the prefix of the file till a101 and rename to empoloyee.txt/salary.txt.
Expected Output:
My try:
import os
path = '/Users/User1/Documents/FilesFolder'
files = os.listdir(path)
for index, file in enumerate(files):
os.rename(os.path.join(path, file), os.path.join(path,file.removeprefix('a101')))
But unable to get expected result.
You may use regular expression:
import os
import re
path = '/Users/User1/Documents/FilesFolder'
files = os.listdir(path)
p = ".*a101.(.+)"
for file in files:
m = re.match(p, file)
if m is not None:
file_new = m.group(1)
print(file_new)
I think this can solve your problem
import os
import glob
# directory Path
path = "/path/to/dir"
# move to directory
os.chdir(path)
# Getting all files in the directory which contains a101
files = glob.glob("*a101*")
for file in files:
splitted = file.split('.')
filename, ext = splitted[-2], splitted[-1]
new_name = f"{filename}.{ext}"
os.rename(file, new_name)
If your file name is following same pattern with 3 . then you can use this for renaming. removeprefix is introduced in python 3.9.
files = ["0. a101.employee.txt", "1. a101.department.txt" ,"2. a101.salary.txt"]
for file in files:
print(".".join(file.split(".")[-2:]))
output:
employee.txt
department.txt
salary.txt
i can suggest you:
files = ["0. a101.employee.txt", "1. a101.department.txt" ,"2. a101.salary.txt"]
for index, file in enumerate(files):
filename = file.split(".")
print(filename[2]+"."+filename[3])
I got the followingoutput:
employee.txt
department.txt
salary.txt

Rename with Counter using Python

I would like to mention that pretty much all of these answers worked well to controlling what it renames, I wanted to place a check on all that worked, only one answer did not work, but if this helps anyone, they will have 3 out of 4 answers that works
My shared script works great, but it renames everything it finds in the directory so please be careful when using my shared script
for super large files I use this python
import os
# Function to rename multiple files
def main():
i = 1000
path="C:/Users/user/Desktop/My Folder/New folder/New folder/"
for filename in os.listdir(path):
my_dest ="(" + str(i) + ")" + ".txt"
my_source =path + filename
my_dest =path + my_dest
# rename() function will
# rename all the files
os.rename(my_source, my_dest)
i += 1
# Driver Code
if __name__ == '__main__':
# Calling main() function
main()
OK, so I am trying to control the counter to only see txt files, if I have .txt, .jpeg, .mpeg,
everything gets rename, how can I control this to only .txt files
One more problem, when I use this Python counter or a batch counter it flips my file names
Example
File_2019.txt - this should be renamed to (1000).txt
FileRecycled_2019.txt - this should be renamed to (1001).txt
Outcome
FileRecycled_2019.txt - this should be renamed to (1000).txt
File_2019.txt - this should be renamed to (1001).txt
When using this method based on filename it flips the order of my files
It takes it out of alphabetical order
I am working on a solution for the names being flipped once I find it I will share it so if it helps others
OK, so I have a underscore remover batch file, and that fixed the flipping
and it renames correctly
for smaller files I will use this
#echo off
Setlocal enabledelayedexpansion
Set "Pattern=_"
Set "Replace= "
For %%a in (*.txt) Do (
Set "File=%%~a"
Ren "%%a" "!File:%Pattern%=%Replace%!"
)
set count=1000
for %%f in (*.txt) do (
set /a count+=1
ren "%%f" "(!count!).txt"
)
You can accomplish this by using the pathlib module
from pathlib import Path
from os import chdir
path = Path.home() / 'desktop' / 'My Folder' / 'New folder' / 'New folder' # The path to use
to_usenum = 1000 # Start num
alltxt = list(path.glob('*.txt')) # Getting all the txt files
chdir(path) # Changing the cwd to the path
for i, txtfile in enumerate(alltxt):
to_usename = f"({to_usenum+i}).txt" # The name to use
txtfile.rename(to_usename)
The pathlib module comes in handy when it comes to files handling. The os module was used in the code to change the current working directory to the path's location because the renamed file will be placed in the current working directory.
You could check the filename has .txt before renaming.
if filename.endswith(".txt"):
os.rename(my_source, my_dest)
i += 1
On the filenames, you haven't specified an order for the names. You could use for filename in sorted(os.listdir(path)): to move through in alphabetical order.
My solution would be:
import os
import glob
def main():
path = "C:/Users/user/Desktop/My Folder/New folder/New folder/"
suffix = '.txt'
files = glob.glob(path + '*' + suffix)
for idx, filename in enumerate(sorted(files)):
os.rename(
filename,
os.path.join(path, f"({1000 + idx})" + suffix)
)
if __name__=="__main__":
main()
This uses glob to get all file paths in the folder with .txt suffix. It also uses enumerate to count each file rather than having to count the i value yourself. The file name is generated using an f-string.
I solved it an easy way:
import os
# Function to rename multiple files
def main():
i = 1000
path = 'C:/Users/user/Desktop/My Folder/New folder/New folder/'
for filename in os.listdir(path):
my_dest = f'({str(i)}).txt'
my_dest = path + my_dest
my_source = path + filename
ext = my_source.split('.')[-1]
if ext == 'txt':
os.rename(my_source, my_dest)
i += 1
# Driver Code
if __name__ == '__main__':
# Calling main() function
main()
my suggestion would be to use glob, give it a go
import os
import glob
# Function to rename multiple files
def main():
i = 1000
path="C:/Users/user/Desktop/My Folder/New folder/New folder/"
files = glob.glob(path + '*.txt')
for filename in files:
my_dest ="(" + str(i) + ")" + ".txt"
my_source =path + filename
my_dest =path + my_dest
# rename() function will
# rename all the files
os.rename(my_source, my_dest)
i += 1
# Driver Code
if __name__ == '__main__':
# Calling main() function
main()
this will search for any file name ending with txt extension

Python - Renaming all files in a directory using a loop

I have a folder with images that are currently named with timestamps. I want to rename all the images in the directory so they are named 'captured(x).jpg' where x is the image number in the directory.
I have been trying to implement different suggestions as advised on this website and other with no luck. Here is my code:
path = '/home/pi/images/'
i = 0
for filename in os.listdir(path):
os.rename(filename, 'captured'+str(i)+'.jpg'
i = i +1
I keep getting an error saying "No such file or directory" for the os.rename line.
The results returned from os.listdir() does not include the path.
path = '/home/pi/images/'
i = 0
for filename in os.listdir(path):
os.rename(os.path.join(path,filename), os.path.join(path,'captured'+str(i)+'.jpg'))
i = i +1
The method rename() takes absolute paths, You are giving it only the file names thus it can't locate the files.
Add the folder's directory in front of the filename to get the absolute path
path = 'G:/ftest'
i = 0
for filename in os.listdir(path):
os.rename(path+'/'+filename, path+'/captured'+str(i)+'.jpg')
i = i +1
Two suggestions:
Use glob. This gives you more fine grained control over filenames and dirs to iterate over.
Use enumerate instead of manual counting the iterations
Example:
import glob
import os
path = '/home/pi/images/'
for i, filename in enumerate(glob.glob(path + '*.jpg')):
os.rename(filename, os.path.join(path, 'captured' + str(i) + '.jpg'))
This will work
import glob2
import os
def rename(f_path, new_name):
filelist = glob2.glob(f_path + "*.ma")
count = 0
for file in filelist:
print("File Count : ", count)
filename = os.path.split(file)
print(filename)
new_filename = f_path + new_name + str(count + 1) + ".ma"
os.rename(f_path+filename[1], new_filename)
print(new_filename)
count = count + 1
the function takes two arguments your filepath to rename the file and your new name to the file

renaming the extracted file from zipfile

I have lots of zipped files on a Linux server and each file includes multiple text files.
what I want is to extract some of those text files, which have the same name across zipped files and save it a folder; I am creating one folder for each zipped file and extract the text file to it. I need to add the parent zipped folder name to the end of file names and save all text files in one directory. For example, if the zipped folder was March132017.zip and I extracted holding.txt, my filename would be holding_march13207.txt.
My problem is that I am not able to change the extracted file's name.
I would appreciate if you could advise.
import os
import sys
import zipfile
os.chdir("/feeds/lipper/emaxx")
pwkwd = "/feeds/lipper/emaxx"
for item in os.listdir(pwkwd): # loop through items in dir
if item.endswith(".zip"): # check for ".zip" extension
file_name = os.path.abspath(item) # get full path of files
fh = open(file_name, "rb")
zip_ref = zipfile.ZipFile(fh)
filelist = 'ISSUERS.TXT' , 'SECMAST.TXT' , 'FUND.TXT' , 'HOLDING.TXT'
for name in filelist :
try:
outpath = "/SCRATCH/emaxx" + "/" + os.path.splitext(item)[0]
zip_ref.extract(name, outpath)
except KeyError:
{}
fh.close()
import zipfile
zipdata = zipfile.ZipFile('somefile.zip')
zipinfos = zipdata.infolist()
# iterate through each file
for zipinfo in zipinfos:
# This will do the renaming
zipinfo.filename = do_something_to(zipinfo.filename)
zipdata.extract(zipinfo)
Reference:
https://bitdrop.st0w.com/2010/07/23/python-extracting-a-file-from-a-zip-file-with-a-different-name/
Why not just read the file in question and save it yourself instead of extracting? Something like:
import os
import zipfile
source_dir = "/feeds/lipper/emaxx" # folder with zip files
target_dir = "/SCRATCH/emaxx" # folder to save the extracted files
# Are you sure your files names are capitalized in your zip files?
filelist = ['ISSUERS.TXT', 'SECMAST.TXT', 'FUND.TXT', 'HOLDING.TXT']
for item in os.listdir(source_dir): # loop through items in dir
if item.endswith(".zip"): # check for ".zip" extension
file_path = os.path.join(source_dir, item) # get zip file path
with zipfile.ZipFile(file_path) as zf: # open the zip file
for target_file in filelist: # loop through the list of files to extract
if target_file in zf.namelist(): # check if the file exists in the archive
# generate the desired output name:
target_name = os.path.splitext(target_file)[0] + "_" + os.path.splitext(file_path)[0] + ".txt"
target_path = os.path.join(target_dir, target_name) # output path
with open(target_path, "w") as f: # open the output path for writing
f.write(zf.read(target_file)) # save the contents of the file in it
# next file from the list...
# next zip file...
You could simply run a rename after each file is extracted right? os.rename should do the trick.
zip_ref.extract(name, outpath)
parent_zip = os.path.basename(os.path.dirname(outpath)) + ".zip"
new_file_name = os.path.splitext(os.path.basename(name))[0] # just the filename
new_name_path = os.path.dirname(outpath) + os.sep + new_file_name + "_" + parent_zip
os.rename(outpath, new_namepath)
For the filename, if you want it to be incremental, simply start a count and for each file, go up by on.
count = 0
for file in files:
count += 1
# ... Do our file actions
new_file_name = original_file_name + "_" + str(count)
# ...
Or if you don't care about the end name you could always use something like a uuid.
import uuid
random_name = uuid.uuid4()
outpath = '/SCRATCH/emaxx'
suffix = os.path.splitext(item)[0]
for name in filelist :
index = zip_ref.namelist().find(name)
if index != -1: # check the file exists in the zipfile
filename, ext = os.path.splitext(name)
zip_ref.filelist[index].filename = f'{filename}_{suffix}.{ext}' # rename the extracting file to the suffix file name
zip_ref.extract(zip_ref.filelist[index], outpath) # use the renamed file descriptor to extract the file
I doubt this is possible to rename file during their extraction.
What about renaming files once they are extracted ?
Relying on linux bash, you can achieve it in a one line :
os.system("find "+outpath+" -name '*.txt' -exec echo mv {} `echo {} | sed s/.txt/"+zipName+".txt/` \;")
So, first we search all txt files in the specified folder, then exec the renaming command, with the new name computed by sed.
Code not tested, i'm on windows now ^^'

Categories