0

I would like to rename images based on part of the name of the folder the images are in and iterate through the images. I am using os.walk and I was able to rename all the images in the folders but could not figure out how to use the letters to the left of the first hyphen in the folder name as part of the image name.

Folder name: ABCDEF - THIS IS - MY FOLDER - NAME

Current image names in folder:

dsc_001.jpg 
dsc_234.jpg
dsc_123.jpg

Want to change to show like this:

ABCDEF_1.jpg
ABCDEF_2.jpg
ABCDEF_3.jpg

What I have is this, but I am not sure why I am unable to split the filename by the hyphen:

import os
from os.path import join

path = r'C:\folderPath'
i = 1

for root, dirs, files in os.walk(path):
    for image in files:
        prefix = files.split(' - ')[0]
        os.rename(os.path.join(path, image), os.path.join(path, prefix + '_' 
        + str(i)+'.jpg'))
        i = i+1
John Kugelman
  • 349,597
  • 67
  • 533
  • 578

1 Answers1

0

Okay, I've re-read your question and I think I know what's wrong.

1.) The os.walk() iterable is recursive, i.e. if you use os.walk(r'C:\'), it will loop through all the folders and find all the files under C drive. Now I'm not sure if your C:\folderPath has any sub-folders in it. If it does, and any of the folder/file format are not the convention as C:\folderPath, your code is going to have a bad time.

2.) When you iterate through files, you are split()ing the wrong object. Your question state you want to split the Folder name, but your code is splitting the files iterable which is a list of all the files under the current iteration directory. That doesn't accomplish what you want. Depending if your ABCDEF folder is the C:\folderPath or a sub folder within, you'll need to code differently.

3.) you have imported join from os.path but you still end up calling the full name os.path.join() anyways, which is redundant. Either just import os and call os.path.join() or just with your current imports, just join().

Having said all of that, here are my edits:

Answer 1:

If your ABCDEF is the assigned folder

import os
from os.path import join

path = r'C:\ABCDEF - THIS - IS - MY - FOLDER - NAME'

for root, dirs, files in os.walk(path):
    folder = root.split("\\")[-1] # This gets you the current folder's name
    for i, image in enumerate(files):
        new_image = "{0}_{1}.jpg".format(folder.split(' - ')[0], i + 1)
        os.rename(join(path, image), join(path, new_image))
    break # if you have sub folders that follow the SAME structure, then remove this break.  Otherwise, keep it here so your code stop after all the files are updated in your parent folder.

Answer 2:

Assuming your ABCDEF's are all sub folders under the assigned directory, and all of them follow the same naming convention.

import os from os.path import join

path = r'C:\parentFolder' # The folder that has all the sub folders that are named ABCDEF...

for i, (root, dirs, files) in enumerate(os.walk(path)):
    if i == 0: continue # skip the parentFolder as it doesn't follow the same naming convention
    folder = root.split("\\")[-1] # This gets you the current folder's name
    for i, image in enumerate(files):
        new_image = "{0}_{1}.jpg".format(folder.split(' - ')[0], i + 1)
        os.rename(join(path, image), join(path, new_image))

Note:

If your scenario doesn't fall under either of these, please make it clear what your folder structure is (a sample including all sub folders and sub files). Remember, consistency is key in determining how your code should work. If it's inconsistent, your best bet is use Answer 1 on each target folder separately.

Changes:

1.) You can get an incremental index without doing a i += 1. enumerate() is a great tool for iterables that also give you the iteration number.

2.) Your split() should be operated on the folder name instead of files (an iterable). In your case, image is the actual file name, and files is the list of files in the current iteration directory.

3.) Use of str.format() function to make your new file format easier to read.

4.) You'll note the use of split("\\") instead of split(r"\"), and that's because a single backslash cannot be a raw string.

This should now work. I ended up doing a lot more research than expected such as how to handle the os.walk() properly in both scenarios. For future reference, a little google search goes a long way. I hope this finally answers your question. Remember, doing your own research and clarity in demonstrating your problem will get you more efficient answers.

Bonus: if you have python 3.6+, you can even use f strings for your new file name, which ends up looking really cool:

new_image = f"{image.split(' - ')[0]}_{i+1}.jpg"
r.ook
  • 13,466
  • 2
  • 22
  • 39
  • Thank you for your help! I did give it a try but still got an error of file not found: Traceback (most recent call last): File "C:/Users/mypla/Desktop/testloop.py", line 11, in os.rename(os.path.join(path, image), os.path.join(path, new_image)) FileNotFoundError: [WinError 2] The system cannot find the file specified: 'C:\\Users\\mypla\\Desktop\\1_Japanese\\dsc_342.jpg' -> 'C:\\Users\\mypla\\Desktop\\1_Japanese\\ dsc_342_2.jpg_2.jpg' – John1276 Jan 12 '18 at 23:00
  • Oh geez, I just read your post a second time and I think the code is fundamentally doing a different thing. I thought the files are under the root folder `path`, but it seems like they're actually in the sub directories? Perhaps share a sample folder/file structure? – r.ook Jan 13 '18 at 01:58
  • Whew, just did a huge edit. I hope that covers it - if not, you'll need to be really clear on your folder/file structure to get a meaningful answer. – r.ook Jan 13 '18 at 04:49
  • Thank you so much! The only thing I had to change was to add the folder in os.rename. os.rename(join(path, folder, image), join(path, folder, new_image)) – John1276 Jan 15 '18 at 16:16