Search code examples
pythonwindows-10

Walk a folder structure, rename files to match sub-folder, keep file extension


I am new to python and coding, as a first project, I am looking to create a python script which will traverse a folder structure and look inside each sub-folder and rename the files within to match the name of the sub-folder.

Example folder structure:

root folder
├── first sub-folder (Batman)
│   ├── filename.extension (joker.pdf)
│   └── filename.differentExtension (bane.jpg)
│
└── second sub-folder
    ├── filename.extension
    └── filename.differentExtension

So after the script has completed, the result would look like the below:

root folder
├── first sub-folder (Batman)
│   ├── filename.extension (Batman.pdf)
│   └── filename.differentExtension (Batman.jpg)
│
└── second sub-folder
    ├── filename.extension
    └── filename.differentExtension

I am looking for recommendations into how to approach this, I was thinking of using os.path.splitext to seperate the filename from the file extension, but i'm unsure how to change the filename to the sub-folder value and then concatenate the filename and file extension back together.


Solution

  • I would use os.walk, and ntpath with a recursive function, to walk all directories and subdirectories...renaming as you go. The following code can absolutely be compressed...but I wanted to make it more explicit to help your understanding of what's happening.

    import os
    import ntpath
    
    print(os.getcwd()) # Information for testing
    rootDir = "/home/user/eclipse-workspace/test" # Will start here
    
    # Create a recursive function. 
    # This function will call itself, to pass in new directories it finds
    def walkit(rootDir):
        # os.walk gives you the name of the directory it's in, 
        # all the subdirs (as a list), 
        # and all the filesnames (as a list)
        for thisDir, thisDir_subDirs, thisDir_files in os.walk(rootDir):
            print("---------------------------")
            print("This Directory =", thisDir, "\nSubdirectories:", thisDir_subDirs, "\nFiles:", thisDir_files)
            # Loop through and change the filenames first
            for filename in thisDir_files:
                # Get JUST the filename with extension
                basename        = ntpath.basename(filename)
                # Split the filename into name + extension 
                name, ext   = os.path.splitext(basename) 
                # Next split the last directory off the full directory path. 
                # Returns a tuple, so you have to take the second element "[1]"
                newname = ntpath.split(thisDir)[1]
                # Python join to create a new name + extension
                newfilename = ''.join([newname, ext])
                # Set the source by joining the current FULL directory path and the FULL old name
                src = os.path.join(thisDir, filename)
                # Set the destination by joining the current FULL path plus the FULL NEW name
                dst = os.path.join(thisDir, newfilename)
                try: # Use try except to catch problems
                    print("Renaming '{}' to '{}' ... ".format(src, dst), end = '') 
                    os.rename(src, dst) # Rename the file
                    print("OK") # Worked
                except Exception as e: # Failed
                    print("FAILED! (ERROR:{})".format(str(e)))
    
            # Now cycle through the list of subdirectories and 
            # send each directory back into the walkit function. 
            # As each loop calls the function, it winds itself a new level deep
            # Each time the function finishes, it "UNwinds" itself one level        
            for rootDir in thisDir_subDirs:
                walkit(rootDir)
    
    # Start the first iteratin by calling the function with the first directory to be parsed
    walkit(rootDir)
    

    OUTPUT:

    /home/user/eclipse-workspace/
    ---------------------------
    This Directory = /home/user/eclipse-workspace/test 
    Subdirectories: ['robin', 'batman'] 
    Files: []
    ---------------------------
    This Directory = /home/user/eclipse-workspace/test/robin 
    Subdirectories: [] 
    Files: ['riddler.jpg', 'penguin.pdf']
    ext= .jpg
    newfilename =  robin.jpg
    Renaming '/home/user/eclipse-workspace/test/robin/riddler.jpg' to '/home/user/eclipse-workspace/test/robin/robin.jpg' ... OK
    ext= .pdf
    newfilename =  robin.pdf
    Renaming '/home/user/eclipse-workspace/test/robin/penguin.pdf' to '/home/user/eclipse-workspace/test/robin/robin.pdf' ... OK
    ---------------------------
    This Directory = /home/user/eclipse-workspace/test/batman 
    Subdirectories: [] 
    Files: ['joker.pdf', 'bane.jpg']
    ext= .pdf
    newfilename =  batman.pdf
    Renaming '/home/user/eclipse-workspace/test/batman/joker.pdf' to '/home/user/eclipse-workspace/test/batman/batman.pdf' ... OK
    ext= .jpg
    newfilename =  batman.jpg
    Renaming '/home/user/eclipse-workspace/test/batman/bane.jpg' to '/home/user/eclipse-workspace/test/batman/batman.jpg' ... OK