I'm working on creating a batch file-renaming application that renames specifically the way I coded it.
Essentially, these files should be renamed from
- RootFolder
- ThisFolder
- ThisItem
- [Incorrectly Labeled] ThatItem
- ThatFolder
- ThisThatItem
- ThatOneSillyItem
- ThisFolder
to
- RootFolder
- ThisFolder
- [ThisFolder] ThisItem
- [ThisFolder] ThatItem
- ThatFolder
- [ThatFolder] ThisThatItem
- [ThatFolder] ThatOneSillyItem
- ThisFolder
This is the working code:
"""
Renames all files in a given directory
"""
from os import path, stat, walk, rename
from os.path import join, sep, isdir
from re import compile, split
from time import time
import codecs
class BatchFileRename:
"""
Renames all files in a given directory
"""
def __init__(self, root):
self._open_file = None
self._prefix = self._label = ""
self._root = root
self._re = compile('\\[[\\w\\s]*\\]?')
self._index = len(self._root.split(path.sep))
self._count = 0
self._size = 0.0
# #######################################
# Public methods
# --------------
def batch_rename(self):
"""
Main class driver.
Renames all files in a given directory (set by constructor)
"""
# Raises an exception if there is no directory
if not isdir(self._root):
raise NotADirectoryError("self._root is empty")
# Opens the output file to document changes
with codecs.open('output' + str(time()) + '.txt', 'wb', "utf-8") as self._open_file:
# Walk through the root folder
for root, dirs, files in walk(self._root):
# Sets the label
self._set_label(root)
# For each label folder, iterate through the files to rename them
for name in files:
self._add_size(root, name) # Adds the file size to counter
new_file = self._rename_file(root, name) # Renames the file
self._write("\"{0}\" renamed to \"{1}\"".format(name, new_file)) # Writes change to output file
self._count += 1 # Counts # of files
self._write()
# Documents total files and sizes at the end.
self._write("Total files: {0}".format(self._count))
self._write("Total size: {0}".format(self._get_total_size()))
# #######################################
# Private methods
# --------------
def _add_size(self, root_path, file_name):
"""
Adds the file size to the counter
:param root_path: folder the file is in
:param file_name: file name
"""
the_path = join(root_path, file_name)
size = stat(the_path).st_size
self._size += size
def _get_total_size(self):
"""
Returns total size (string)
:return: Formatted string of total size.
"""
index = 0
tier = ["B", "KB", "MB", "GB", "TB"]
while self._size / 1024 >= 1:
self._size /= 1024.0
index += 1
return "{0:.2f} {1}".format(self._size, tier[index])
def _rename_file(self, root_path, file_name):
"""
Renames the given file
:param root_path: Folder the file is in
:param file_name: file name
:return: New file name.
"""
# If root_path is the root folder,
# just assign root_path to split_names
if root_path == self._root:
split_names = file_name
# Otherwise,
# split it based on regex
else:
split_names = split(pattern=self._re, string=file_name)
# Arrange a new file_name and strip the extra whitespaces
new_file = self._prefix + ' ' + ''.join(split_names).replace(' ', ' ')
new_file = new_file.strip()
# Rename the file
rename(join(root_path, file_name), join(root_path, new_file))
return new_file
def _set_label(self, root_path):
"""
Sets the label
:param root_path: the existing folder
"""
dir_name = None if self._root == root_path else root_path.split(sep)[self._index]
if self._label != dir_name and dir_name is not None:
self._write()
self._write("*"*40)
self._write("Leaving the \"{0}\" folder.".format(self._label))
self._write("Opened \"{0}\" folder...".format(dir_name))
self._write("*"*40)
self._write()
self._label = dir_name
self._prefix = "[{0}]".format(self._label) if "[" not in self._label else self._label
def _write(self, message="", new_line=True):
"""
Writes the message in the output file
:param message: The message to write
:param new_line: New line is necessary
"""
self._open_file.write(message + ("\n" if new_line or len(message) > 0 else ""))
if __name__ == '__main__':
br = BatchFileRename(r"Z:\Private")
br.batch_rename()
If I could get a feedback on this code, that would be awesome!
Thank you!