Python - Batch rename to timestamp - python

i'm pretty new to Python and i tried writing a code that takes a list of files (1.pdf,2.pdf,3.pdf etc') and renames it to the time it was created.
I'm using Ubuntu 21 and python 3.8
import time
import os
extension = ".pdf"
folder_path = "/home/user/Downloads"
file_list = []
for filename in os.listdir(folder_path):
if filename.endswith(extension) and filename not in file_list:
full = folder_path + '/' + filename
t = os.path.getctime(full)
t_str = time.ctime(t)
t_obj = time.strptime(t_str)
format_t = time.strftime("%Y%m%d_%H%M%S", t_obj)
full_path = os.path.join(folder_path, filename)
os.rename(full_path, os.path.join(folder_path, format_t + extension))
name_sum = format_t + extension
file_list.append(name_sum)
When i run the code files are deleted and only 1 file is left.
Please help me understand what am i doing wrong.

They are all renamed to the same name. You should add a check like:
new_name = os.path.join(folder_path, format_t + extension)
if os.path.isfile(new_name):
raise Exception(new_name + " exists already")
os.rename(full_path, new_name)
or handling files that were created at the exact same second by adding some suffix or something like that

Your code seems correct and worked correctly on my system.
You could try adding an iterator counter number to differentiate the names in the loop. The uniqueness of the names may be caused of the "format_t" you add producing the same within the loop may be cause of the execution time or an internal bug within the time function yielding the same strings.

Related

How to move a copy of specific files in one folder to another folder based on having the latest "Created date" in Python?

I have a folder that contains about 5,000 files and I need to move the files that start with certain names to another folder. The issue is that I need to only take the file with the most recent created date for that name.
For example:
Let's say one of the names I've been given is "Sam Thompson" and there are three files that meet that criteria...
Sam_Thompson_02012023
Sam_Thompson_02052023
Sam_Thompson_02102023 (let's assume this is the most recently created file)
I need to move only the last file to a different folder as it was created most recently.
I have figured out how to move files based on the name piece but have struggled with finding resources online that relate to my issue very closely.
The below code works perfectly -- it moves the files that start with Sam_Thompson to the appropriate folder. The part that doesn't work is the part that's commented out: and max(file_name, key=os.path.getctime):
I think I'm going about getting the max date by file name incorrectly so any input is appreciated. Most of the material I've looked at online is specific to scenarios where you just want to return the name of the latest file (not move it) and it's typically looking across the whole folder not by each given name.
import shutil
import os
source_folder = 'insert path'
destination_folder = 'insert path'
s = 'Sam_Thompson'
for file_name in os.listdir(source_folder):
source = source_folder + file_name
destination = destination_folder + file_name
if os.path.isfile(source) and file_name.startswith(s): #and max(file_name, key=os.path.getctime):
shutil.copy(source, destination)
print('Copied:', file_name)
The issue is that your file_name is only looking at one file at a time. You could store the date and then check if subsequent files have a more recent date to find it, but it's easier just to pull all the valid files at once with list comprehension.
source_folder = ''
destination_folder = ''
s = ''
valid_files = [file for file in os.listdir(source_folder) if file.startswith(s)]
most_recent = max(valid_files, key = lambda x: os.path.getctime(os.path.abspath(source_folder) + os.sep + x))
source = source_folder + os.sep + most_recent
destination = destination_folder + os.sep + most_recent
shutil.copy(source, destination)

FileNotFoundError when trying to use os.rename

I've tried to write some code which will rename some files in a folder - essentially, they're listed as xxx_(a).bmp whereas they need to be xxx_a.bmp, where a runs from 1 to 2000.
I've used the inbuilt os.rename function to essentially swap them inside of a loop to get the right numbers, but this gives me FileNotFoundError [WinError2] the system cannot find the file specified Z:/AAA/BBB/xxx_(1).bmp' -> 'Z:/AAA/BBB/xxx_1.bmp'.
I've included the code I've written below if anyone could point me in the right direction. I've checked that I'm working in the right directory and it gives me the directory I'm expecting so I'm not sure why it can't find the files.
import os
n = 2000
folder = r"Z:/AAA/BBB/"
os.chdir(folder)
saved_path = os.getcwd()
print("CWD is" + saved_path)
for i in range(1,n):
old_file = os.path.join(folder, "xxx_(" + str(i) + ").bmp")
new_file = os.path.join(folder, "xxx_" +str(i)+ ".bmp")
os.rename(old_file, new_file)
print('renamed files')
The problem is os.rename doesn't create a new directory if the new name is a filename in a directory that does not currently exist.
In order to create the directory first, you can do the following in Python3:
os.makedirs(dirname, exist_ok=True)
In this case dirname can contain created or not-yet-created subdirectories.
As an alternative, one may use os.renames, which handles new and intermediate directories.
Try iterating files inside the directory and processing the files that meet your criteria.
from pathlib import Path
import re
folder = Path("Z:/AAA/BBB/")
for f in folder.iterdir():
if '(' in f.name:
new_name = f.stem.replace('(', '').replace(')', '')
# using regex
# new_name = re.sub('\(([^)]+)\)', r'\1', f.stem)
extension = f.suffix
new_path = f.with_name(new_name + extension)
f.rename(new_path)

Moving folders to a directory according to their name

I'm new in Python and am currently developing an application that moves folders to a specific directory according their folder name.
I get no errors nor warnings but the application won't move the folders.
Here's the code:
import os
import shutil
def shorting_algorithm():
file_list = []
directory = input("Give the directory you want to search.")
newdir = "D:\\Torrents\\Complete\\Udemy"
name = "'" + input("Give the name of the files you want to move.") + "'"
xlist = os.listdir(directory)
print(xlist)
print(name)
for files in xlist:
if name in files:
shutil.move(directory + files,newdir)
shorting_algorithm()
Note: I tried removing "'" +...+"'" but it didn't work either. Any ideas?
Don't forget the file separator while joining the file and the directory.
for files in xlist:
#if name in files: EDIT: As pointed out by IosiG, Change here too
if name == files:
shutil.move(directory + files,newdir) #make changes here
directory + '\\' + files.
#or
import os
os.path.join(directory,files)
You don't need the for loop or the if statement. You already identified the file in the main code block. Since you are specifying a directory and a filename explicitly, you don't need to do a loop through a directory list to find one. That's more for when you want a program to automatically find a file that fits some particular condition. Try this:
import os
import shutil
def shorting_algorithm():
directory = input("Give the directory you want to search.")
newdir = r'D:\Torrents\Complete\Udemy'
name = "\\" + input("Give the name of you files you want to move.")
print(name)
print(directory)
shutil.move(directory + name,newdir)
shorting_algorithm()
Getting rid of the extra quotes and adding your slashes to the path, turning your newdir into a raw string to avoid escapes, and getting rid of the for loop should make this code work. I just tested it out and it works here.
The problem is your loop, you mixed two ways of iterating.
What happens is the following:
for files in xlist: #loop through the names of the files
if name in files: # look for the name of your file inside the name of another file
shutil.move(directory + files,newdir)
What should be done is the following:
if name in xlist:
shutil.move(directory + name,newdir)
or also
for file in xlist: # only reason for this is if you want input check
if str(file) == name:
# do whatever you need
Also, you have to remove the "'" +...+"'" from the input, since you are entering those into the string, which will make the comparison quite messy.
I'd recommend also to use raw_input instead of input.
Thank you all for your answers, the problem was easily solved by using "shutil.move(directory + '\' + files,newdir)" as suggested.
import os
import shutil
def shorting_algorithm():
directory = input("Give the directory you want to search.")
name = input("Give the name of you files you want to move.")
newdir = input("Give the new directory.")
xlist = os.listdir(directory)
for files in xlist:
if name in files:
shutil.move(directory + '\\' + files,newdir)
shorting_algorithm()

Cannot find the file specified when batch renaming files in a single directory

I've created a simple script to rename my media files that have lots of weird periods and stuff in them that I have obtained and want to organize further. My script kinda works, and I will be editing it to edit the filenames further but my os.rename line throws this error:
[Windows Error: Error 2: The system cannot find the file specified.]
import os
for filename in os.listdir(directory):
fcount = filename.count('.') - 1 #to keep the period for the file extension
newname = filename.replace('.', ' ', fcount)
os.rename(filename, newname)
Does anyone know why this might be? I have a feeling that it doesn't like me trying to rename the file without including the file path?
try
os.rename(filename, directory + '/' + newname);
Triton Man has already answered your question. If his answer doesn't work I would try using absolute paths instead of relative paths.
I've done something similar before, but in order to keep any name clashes from happening I temporarily moved all the files to a subfolder. The entire process happened so fast that in Windows Explorer I never saw the subfolder get created.
Anyhow if you're interested in looking at my script It's shown below. You run the script on the command line and you should pass in as a command-line argument the directory of the jpg files you want renamed.
Here's a script I used to rename .jpg files to multiples of 10. It might be useful to look at.
'''renames pictures to multiples of ten'''
import sys, os
debug=False
try:
path = sys.argv[1]
except IndexError:
path = os.getcwd()
def toint(string):
'''changes a string to a numerical representation
string must only characters with an ordianal value between 0 and 899'''
string = str(string)
ret=''
for i in string:
ret += str(ord(i)+100) #we add 101 to make all the numbers 3 digits making it easy to seperate the numbers back out when we need to undo this operation
assert len(ret) == 3 * len(string), 'recieved an invalid character. Characters must have a ordinal value between 0-899'
return int(ret)
def compare_key(file):
file = file.lower().replace('.jpg', '').replace('dscf', '')
try:
return int(file)
except ValueError:
return toint(file)
#files are temporarily placed in a folder
#to prevent clashing filenames
i = 0
files = os.listdir(path)
files = (f for f in files if f.lower().endswith('.jpg'))
files = sorted(files, key=compare_key)
for file in files:
i += 10
if debug: print('renaming %s to %s.jpg' % (file, i))
os.renames(file, 'renaming/%s.jpg' % i)
for root, __, files in os.walk(path + '/renaming'):
for file in files:
if debug: print('moving %s to %s' % (root+'/'+file, path+'/'+file))
os.renames(root+'/'+file, path+'/'+file)
Edit: I got rid of all the jpg fluff. You could use this code to rename your files. Just change the rename_file function to get rid of the extra dots. I haven't tested this code so there is a possibility that it might not work.
import sys, os
path = sys.argv[1]
def rename_file(file):
return file
#files are temporarily placed in a folder
#to prevent clashing filenames
files = os.listdir(path)
for file in files:
os.renames(file, 'renaming/' + rename_file(file))
for root, __, files in os.walk(path + '/renaming'):
for file in files:
os.renames(root+'/'+file, path+'/'+file)
Looks like I just needed to set the default directory and it worked just fine.
folder = r"blah\blah\blah"
os.chdir(folder)
for filename in os.listdir(folder):
fcount = filename.count('.') - 1
newname = filename.replace('.', ' ', fcount)
os.rename(filename, newname)

Moving files and creating directories if certain file type in python

This is probably a simple question, but I'm brand new to python and programming in general.
I'm working on a simple program to copy/move .mp3 files from on location to another while mirroring the directory structure of the source location. What I have so far works, however it also creates new folders in the destination location even if the source folder contained no mp3 files. I only want to create the new directories if the source contains .mp3s, otherwise it could lead to a bunch of empty folders in the destination.
Here is what I have so far:
import os
import shutil #Used for copying files
##CONFIG
source_dir = "C:\Users\username\Desktop\iTunes\\" #set the root folder that you want to scan and move files from. This script will scan recursively.
destPath = "C:\Users\username\Desktop\converted From iTunes" #set the destination root that you want to move files to. Any non-existing sub directories will be created.
ext = ".mp3" #set the type of file you want to search for.
count = 0 #initialize counter variable to count number of files moved
##
##FIND FILES
for dirName, subdirList, fileList in os.walk(source_dir):
#set the path for the destination folder(s)
dest = destPath + dirName.replace(source_dir, '\\')
#if the source directory doesn't exist in the destination folder
#then create a new folder
if not os.path.isdir(dest):
os.mkdir(dest)
print('Directory created at: ' + dest)
for fname in fileList:
if fname.endswith(ext) :
#determine source & new file locations
oldLoc = dirName + '\\' + fname
newLoc = dest + '\\' + fname
if os.path.isfile(newLoc): # check to see if the file already exists. If it does print out a message saying so.
print ('file "' + newLoc + fname + '" already exists')
if not os.path.isfile(newLoc): #if the file doesnt exist then copy it and print out confirmation that is was copied/moved
try:
shutil.move(oldLoc, newLoc)
print('File ' + fname + ' copied.')
count = count + 1
except IOError:
print('There was an error copying the file: "' + fname + '"')
print 'error'
print "\n"
print str(count) + " files were moved."
print "\n"
so if the folder structure is something like:
root->
band 1->
album name->
song.m4a,
song2.m4a
right now it will create all those folders in the destination driectory, even though there are no .mp3s to copy.....
Any help is appreciated!
I think I would create my own wrapper around copy for this sort of thing:
def fcopy(src,dest):
"""
Copy file from source to dest. dest can include an absolute or relative path
If the path doesn't exist, it gets created
"""
dest_dir = os.path.dirname(dest)
try:
os.makedirs(dest_dir)
except os.error as e:
pass #Assume it exists. This could fail if you don't have permissions, etc...
shutil.copy(src,dest)
Now you can just walk the tree calling this function on any .mp3 file.
The simplest thing to do I can think of for your existing code would be to just make it skip over any folders that don't have any .mp3 files in them. This can easily be done by adding the following items and if statement to the top of your loop. The itertools.ifilter() and fnmatch.fnmatch() functions can be used together to simplify checking for files with the proper extension.
from itertools import ifilter
from fnmatch import fnmatch
ext = '.mp3'
fnPattern = '*'+ext
for dirName, subdirList, fileList in os.walk(source_dir):
if not any(ifilter(lambda fname: fnmatch(fname, fnPattern), fileList)):
print ' skipping "{}"'.format(dirName)
continue
...
You will also have to change the os.mkdir(dest) to os.makedirs(dest) in the code further down to ensure that any subdirectories skipped by earlier iterations get created when there's a need to copy files to a corresponding subbranch of the destination directory.
You could optimize things a bit by creating and saving a possibly empty iterator of matching files that have the extension, and then use it again later to to determine what files to copy:
from itertools import ifilter
from fnmatch import fnmatch
ext = '.mp3'
fnPattern = '*'+ext
for dirName, subdirList, fileList in os.walk(source_dir):
# generate list of files in directory with desired extension
matches = ifilter(lambda fname: fnmatch(fname, fnPattern), fileList)
# skip subdirectory if it does not contain any files of interest
if not matches:
continue
...
... create destination directory with os.makedirs()
...
# copy each file to destination directory
for fname in matches:
... copy file
Would shutils.copytree not do what you want in fewer lines?

Categories