Python: Changing filenames and folder names in all folders and subfolders - python

I want to change the file names and folder names in a given directory and all subfolders. My folder structure is as follows:
top directory
file1
file2
folder1
file1
file2
file3
file4
folder2
file1
file2
file3
file4
I get the following error when executing the code below. I already checked the forums, but couldn't find a solution. Could someone please help me solve this issue and let me know what I need to do to get the program working?
Or is there a better solution for renaming files and folders in a tree?
Error message
FileNotFoundError: [WinError 2] The system cannot find the file specified: 'Filename 1' -> 'filename_1'
Code
#Change file names and folder names in a given directory and all its
subfolders
import os
os.chdir("path\\to\\folder")
print(os.getcwd())
#Walk the directory and change the file names and folder names in all folders and subfolders.
for root, dirs, files in os.walk("path\\to\\folder"):
for dir_name in dirs:
os.rename(dir_name, dir_name.replace(" ", "_").lower())
for file_name in files:
os.rename(file_name, file_name.replace(" ", "_").lower())
#Print done once all files have been renamed.
print("done")

You need to use root otherwise the rename can't find the path:
for root, dirs, files in os.walk("path/to/folder"):
for name in dirs + files:
os.rename(os.path.join(root, name), os.path.join(root, name.replace(" ", "_").lower()))

could it be that you're walking on a folder while renaming it so that it can't be found?
looks like you first need to rename the files and only then the dirs (and even then - make sure it's bottom up)

Try to change the filename first, otherwise you'll change the dir_name and lose reference.

Following solution works most of the time, still issues like same name files may exist after normalizing the name.
import os
os.chdir("path/to/dir")
print(os.getcwd())
#Walk the directory and change the file names and folder names in all folders and subfolders.
for root, dirs, files in os.walk("path/to/dir", topdown=False):
for file_name in files:
new_name = file_name.replace(" ", "_").lower()
if (new_name != file_name):
os.rename(os.path.join(root, file_name), os.path.join(root, new_name))
for dir_name in dirs:
new_name = dir_name.replace(" ", "_").lower()
if (new_name != dir_name):
os.rename(os.path.join(root, dir_name), os.path.join(root, new_name))

Here I copied all files inside of each subfolder to another path.
First use os.listdir() to move through each folder, then use it to move through files which are inside of the folder path. Finally use os.rename() to rename file name. Here, I changed file name to folder name_file name which is "folder_file":
path = 'E:/Data1'
path1 = 'E:/Data2'
for folder in os.listdir(path):
for file in os.listdir(path + '/'+ folder):
src = path + '/' + folder + '/' + file
des = path1 + '/' + folder + '_' +file
os.rename(src, des)

Related

Saving Multiple Local/Offline Files to Target Folder with OS Module

I am trying to move all files that are in Just source_path to the target_path.
Here is the code:
import os
target_path = 'C:/Users/Justi/source/repos/GUI Developmentv3/Test 02' + '\\'
source_path ='C:/Users/Justi/source/repos/GUI Developmentv3/' + '\\'
for path, dir, files in os.walk(source_path):
if files:
for file in files:
if not os.path.isfile(target_path + file):
os.rename(path + '\\' + file, target_path + file)
However, this also moves other files that are in the sub-directory folders of the source folder into the target folder.
May I check how I could change the code to only move files at the exact directory of source_path without affecting files in source_path's sub-dictionary? Thank you in advance.
I think the problem is the usage of os.walk, because it walks the whole tree. See the docs:
Generate the file names in a directory tree by walking the tree either top-down or bottom-up.
You are only interested in the contents of a particular folder, so os.listdir is more suitable:
Return a list containing the names of the entries in the directory given by path.
The following code will iterate over the files in the source dir, and move only the files into the target dir.
import os
import shutil
source = "source"
target = "target"
for f in os.listdir(source):
print(f"Found {f}")
if os.path.isfile(os.path.join(source, f)):
print(f"{f} is a file, will move it to target folder")
shutil.move(os.path.join(source, f), os.path.join(target, f))

How to rename unzipped files in Python?

I have the following structure:
Folder1
ZZ-20201201-XX.zip
Folder2
XX-20201201-XX.zip
XX-20201202-XX.zip
Folder3
YY-20201201-XX.zip
YY-20201202-XX.zip
With below code Im creating a counterpart of Folder1, Folder2 and Folder3 and directly unzipping the zipped files inside those 3 folders. So I receive this:
Folder1
ZZ-.txt
Folder2
XX-.txt
Folder3
YY.txt
As you can see the files lose the date once they get unzipped so if a folder contains 2 zipped files they will get the same name and thus the files will be rewritten. Now I want to add the date of the zipped files to the files once they are unzipped. How can I do this?
import fnmatch
pattern = '*.zip'
for root, dirs, files in os.walk(my_files):
for filename in fnmatch.filter(files, pattern):
path = os.path.join(root, filename)
date_zipped_file = re.search('-(.\d+)-', filename).group(1) #<-- this is the date of the zipped files and I want this to be included in the name of the unzipped files once they get unzipped.
# Store the new directory so that it can be recreated
new_dir = os.path.normpath(os.path.join(os.path.relpath(path, start=my_files), ".."))
# Join your target directory with newly created directory
new = os.path.join(counter_part, new_dir)
# Create those folders, works even with nested folders
if (not os.path.exists(new)):
os.makedirs(new)
zipfile.ZipFile(path).extractall(new)
my desired outcome:
Folder1
ZZ-20201201.txt
Folder2
XX-20201201.txt
XX-20201202.txt
Folder3
YY-20201201.txt
XX-20201202.txt
You could just rename the files after you have unzipped each folder. Something like this:
#get all files in that unzipped folder
files = os.listdir(path)
#rename all files in that dir
for file in files:
filesplit = os.path.splitext(os.path.basename(file))
os.rename(os.path.join(path, file), os.path.join(path, filesplit[0]+'_'+date_zipped_file+filesplit[1]))
but that also renames files which might actually have already a date in the name. So you would also need to integrate a check if the file was already renamed. Either by maintaining a list with file names or a simple regex which looks for 8 digit string between a '_' and a '.', e.g. text_20201207.txt.
#get all files in that unzipped folder
files = os.listdir(path)
#rename all files in that dir
for file in files:
filesplit = os.path.splitext(os.path.basename(file))
if not re.search(r'_\d{8}.', file):
os.rename(os.path.join(path, file), os.path.join(path, filesplit[0]+'_'+date_zipped_file+filesplit[1]))
your final solution would then look something like this:
import fnmatch
pattern = '*.zip'
for root, dirs, files in os.walk(my_files):
for filename in fnmatch.filter(files, pattern):
path = os.path.join(root, filename)
date_zipped_file = re.search('-(.\d+)-', filename).group(1) #<-- this is the date of the zipped files and I want this to be included in the name of the unzipped files once they get unzipped.
# Store the new directory so that it can be recreated
new_dir = os.path.normpath(os.path.join(os.path.relpath(path, start=my_files), ".."))
# Join your target directory with newly created directory
new = os.path.join(counter_part, new_dir)
# Create those folders, works even with nested folders
if (not os.path.exists(new)):
os.makedirs(new)
zipfile.ZipFile(path).extractall(new)
#get all files in that unzipped folder
files = os.listdir(new)
#rename all files in that dir
for file in files:
filesplit = os.path.splitext(os.path.basename(file))
if not re.search(r'_\d{8}.', file):
os.rename(os.path.join(new, file), os.path.join(new, filesplit[0]+'_'+date_zipped_file+filesplit[1]))

renaming all images in folders using the name of the folder

I have a lot of folders. in each folder, there is an image. I want to rename all of the images with the name of its folder.
For example:
Folder "1" has an image "273.jpg" I want to change it into the "1.jpg" and save it in another directory.
This is what I have done so far:
import os
import pathlib
root = "Q:/1_Projekte/2980/"
for path, subdirs, files in os.walk(root):
for name in files:
print (pathlib.PurePath(path, name))
os.rename(os.path.join(path, name), os.path.join(path, os.path.basename(path)))
print(os.path.basename(path))
The problem is that it works just for the first folder, then it jumps out with the error:
this file is already available...
the tree of folders and the images are like this:
Q:/1_Projekte/2980/1/43425.jpg
Q:/1_Projekte/2980/2/43465.jpg
Q:/1_Projekte/2980/3/43483.jpg
Q:/1_Projekte/2980/4/43499.jpg
So there is just one file in each directory!
Probably you have some hidden files in those directories. Check it out. If those files are not jpg, you can use following code:
for path, subdirs, files in os.walk(root):
for name in files:
extension = name.split(".")[-1].lower()
if extension != "jpg":
continue
os.rename(os.path.join(path, name), os.path.join(path, os.path.basename(path) + "." + extension))
print(os.path.basename(path))
This code extracts the extension of the file and checks if it is equal to the jpg. If file extension is not jpg, so continue statement will run and next file will check. If file type is jpg, script renames it. Also this code adds original file extension to the new name. Previous code didn't handle that.
I hope this helpe you.
Maybe this might help...
import os
root = "Q:/1_Projekte/2980/"
subdirs = [x for x in os.listdir(root) if os.path.isdir(x)]
for dir_name in subdirs:
dir_path = root + dir_name + '/'
files = os.listdir(dir_path)
print(dir_name)
print(files)
for i in files:
counter = 1
extension = i.split('.')[-1]
new_name = dir_name + '.' + extension
while True:
try:
os.rename(dir_path + i, dir_path + new_name)
break
except:
# If the file exists...
new_name = dir_name + '({})'.format(counter) + '.' + extension
counter += 1
This code ensures that even if a file with the existing name happens to exist, it will be suffixed with a number in brackets.

How to loop over directories and rename files?

Im ney to python and therefore apologize for the triviality of my question:
I have the following file structure, where a .csv file with employee is saved on daily basis:
dir/2012-01-01/employee.csv.bz2
dir/2012-01-02/employee.csv.bz2
dir/2012-01-03/employee.csv.bz2
dir/2012-01-04/employee.csv.bz2
dir/2012-01-05/employee.csv.bz2
I would like to go through each file and rename it. Afterwards I would like to save the new files in one common directory dir/common. What I tried:
import sys
import os
path = 'dir/'
for folderName, subfolders, filenames in os.walk(path):
for filename in filenames:
infilename = os.path.join(path, filename)
newname = infilename.replace('.csv.bz2', '.csv')
output = os.rename(infilename, newname)
But I get the error:
output = os.rename(infilename, newname)
FileNotFoundError: [WinError 2] The system cannot find the file specified: 'dir/employee.csv.bz2' -> 'dir/employee.csv'
Not sure what Im doing wrong.
Use folderName instead of path in os.path.join(path, filename) because folderName has full path to subfolder.
infilename = os.path.join(folderName, filename)
If you want to save in one folder then use this folder in newname and rename() will move file to new place.
newname = os.path.join('dir', 'common', filename.replace('.csv.bz2', '.csv'))
BTW: But you have to create this folder first.
os.mkdir('dir/common')
or to create folder and all intermediate folders from path
os.makedirs('dir/common/many/sub/folders/to/create')
infilename = os.path.join(path, filename)
You are missing the subfolder, which is evident from the error message: 'dir/employee.csv.bz2'.

Python loop through folders and rename files

I am trying to go through a bunch of folders and go into each one and rename specific files to different names. I got stuck on just the loop through folders part.
My file system looks as follows:
Root Directory
Folder
File1
File2
File3
Folder
File1
File2
File3
The code I have is:
os.chdir(rootDir)
for folder in os.listdir():
print(folder)
os.chdir(rootDir + 'folder')
for f in os.listdir():
print(f)
os.chdir(rootDir)
So in my mind it will go through the folders then enter the folder and list the files inside then go back to the root directory
Have a look at os.walk
import os
for dir, subdirs, files in os.walk("."):
for f in files:
f_new = f + 'bak'
os.rename(os.path.join(root, f), os.path.join(root, f_new))
You need os.walk. It returns a 3-tuple (dirpath, dirnames, filenames) that you can iterate.
def change_files(root_dir,target_files,rename_fn):
for fname in os.listdir(root_path):
path = os.path.join(root_path,fname)
if fname in target_files:
new_name = rename_fn(fname)
os.move(path,os.path.join(root_path,new_name)
def rename_file(old_name):
return old_name.replace("txt","log")
change_files("/home/target/dir",["File1.txt","File2.txt"],rename_file)

Categories