Batch change a file name in Python by adding a string or sequential number before and after the file name

Money and Business

Rename in bulk using the os module and glob module.

Use the os module and glob module to change and rename the file names in a folder in bulk by adding strings or sequential numbers before and after the file names.

Example file structure

Take the following file structure as an example. In this case, it is assumed that there are only files (no folders) in the folder.

└── testdir
    ├── a.jpg
    ├── b.jpg
    ├── c.jpg
    ├── d.jpg
    └── e.jpg

Things to keep in mind

Since the process involves renaming the file, save the original file separately so that it can be saved in case of failure.

Get the file list with the glob module

The glob module will find all pathnames that match the specified pattern according to the rules used by the Unix shell.
glob — Unix style pathname pattern expansion — Python 3.10.0 Documentation

For example, the following function can be used to get a list of file and directory names in the current directory.
The argument can be an absolute path or a relative path.

In this example, it would look like the following.

import glob

# => ['./testdir/a.jpg', './testdir/b.jpg', './testdir/c.jpg', './testdir/d.jpg', './testdir/e.jpg']

Instead of a.jpg, you can get the following, with the argument path added.

You can also use wildcards (*) to get only specific extensions, as shown below.

The following pattern matching can be used.

  • *: Matches everything.
  • ?Matches any single character.
  • [abc]: Matches a single character from a, b, or c.
  • [!abc]: Matches a single character other than a, b, or c

Rename with os.rename()

os.rename(src, dst, *, src_dir_fd=None, dst_dir_fd=None)
Rename the file or directory src to dst.
os — Miscellaneous operating system interfaces — Python 3.10.0 Documentation

Use the function rename() of the os module, which will rename it as the name suggests.

import os
os.rename('./testdir/a.jpg', './testdir/a_000.jpg')

Then, a.jpg will be renamed to a_000.jpg.

Generating zero-filled sequential numbers with str.format()

For example, when adding sequential numbers to dozens of files, we want to use “00” or “11” instead of “0” or “1”. If you want to fill in the zeros in this way, use the str.format() method.

Performs string formatting operations. The string that invokes this method can contain normal characters or substitution fields separated by {}.Built-in Types — Python 3.10.0 Documentation

Syntax of format specification strings
The formatting string contains the “replacement field” enclosed in curly brackets {}.

The syntax of the replacement field is as follows:
replacement_field ::= "{" [field_name] ["!" conversion] [":" format_spec] "}"

In simpler terms, the replacement field starts with field_name, which causes the value of the specified object to be formatted and inserted into the output instead of the replacement field. After the field_name, the conversion field can be followed by an exclamation mark '! After the field_name, the conversion field can be followed by an exclamation mark '! The format_spec can be written with a colon ':' at the end. This specifies the non-default format of the value to be replaced.
string — Common string operations — Python 3.10.0 Documentation

If you want to fill it with 0 for now, do the following.

# 3を2桁でゼロ埋め
# => 03

# Fill in the zeros with three and four digits for 4 and 6, respectively.
print('{0:03d}, {1:04d}'.format(4, 6))
# => 004, 0006

Example of code to add a string/sequential number before a file

First, get the file name with os.path.basename(). Then, add a string or sequential number in front of the file name, and concatenate it with the original path with os.path.join().

The following example adds img_ to the front of all file names.

import os
import glob

path = "./testdir"
files = glob.glob(path + '/*')

for f in files:
    os.rename(f, os.path.join(path, 'img_' + os.path.basename(f)))

The result is as follows.

└── testdir
    ├── img_a.jpg
    ├── img_b.jpg
    ├── img_c.jpg
    ├── img_d.jpg
    └── img_e.jpg

If you want to add sequential numbers, change the for statement to something like this: enumerate() to get the numbers counted in order from 0. In this case, the number is filled with three digits.

for i, f in enumerate(files):
    os.rename(f, os.path.join(path, '{0:03d}'.format(i) +
                              '_' + os.path.basename(f)))

Here's the result.

└── testdir
    ├── 000_a.jpg
    ├── 001_b.jpg
    ├── 002_c.jpg
    ├── 003_d.jpg
    └── 004_e.jpg

If you want to start with 1 instead of 0, set the second argument of enumerate to 1.

for i, f in enumerate(files, 1):
    os.rename(f, os.path.join(path, '{0:03d}'.format(i) +
                              '_' + os.path.basename(f)))

It goes like this.

└── testdir
    ├── 001_a.jpg
    ├── 002_b.jpg
    ├── 003_c.jpg
    ├── 004_d.jpg
    └── 005_e.jpg

Example of code to add a string/sequential number after a file

Use os.path.splitext() to split the file into extension and root path, and then add strings or sequential numbers to the root path. In the following example, _img is added after all file names.

import os
import glob

files = glob.glob('./testdir/*')

for f in files:
    ftitle, fext = os.path.splitext(f)
    os.rename(f, ftitle + '_img' + fext)

The result is this.

└── testdir
    ├── a_img.jpg
    ├── b_img.jpg
    ├── c_img.jpg
    ├── d_img.jpg
    └── e_img.jpg

As with adding a string/sequential number before a file, change the for statement when adding a sequential number.

for i, f in enumerate(files):
    ftitle, fext = os.path.splitext(f)
    os.rename(f, ftitle + '_' + '{0:03d}'.format(i) + fext)
└── testdir
    ├── a_000.jpg
    ├── b_001.jpg
    ├── c_002.jpg
    ├── d_003.jpg
    └── e_004.jpg
Copied title and URL