Python: Recreate file path with shorter name(s)?

Viewed 75

D:\MyDir contains a huge number of directories with or without subdirectories which may or may not contain one or more files.

Some of them have very long name +/- very long name for the subdirectories and/or file(s) too which leads to a huge path name for that file.

e.g.

D:\MyDir:
"Very large directory name"\
    "Very large directory name"\ 
#OPTIONAL
#other or the same name repeating one or more times
        "normal dir"\ #optional
             Long_or_normal_name_MyFile.html and Long_or_normal_name_MyFile.html and so on...

I want to create a Python script that:

  1. Move the file(s) to the first directory (base directory) named "Very large directory name".
  2. Rename the file with a shorter name.
  3. Rename the base directory with a shorter name and after that remove empty directories left behind.

To move a file or a folder I can do that with shutil.move().

With this code I list all the files from a directory and store them into a list:

from os import listdir
from os.path import isfile, join
onlyfiles = [f for f in listdir(mypath) if isfile(join(mypath, f))]

And this line will list only first level directory from D:\MyDir and store them into a list:

[ name for name in os.listdir(thedir) if os.path.isdir(os.path.join(thedir, name)) ]

But how to do it further in order to do what I need to do?

Forgot to say that D:\MyDir contains also directories and files that don't need to be renamed and/or moved.

Thank you in advance!

1 Answers

You could traverse each folder that you wanted to change to the bottom level. Move each file at the bottom up two levels and change their names. Then remove any empty folders on your way back up. Then finally change the name of the directory itself.

Here is an example. Without knowing what your planning on renaming each folder and file I just took their current names and cut them in half. I do preserve file extensions and check to make sure the renamed files aren't overwriting each other by adding unique numbers to the end.

import os, shutil
from pathlib import Path

def traverse(current):
    if current.is_file(): # if current path is a file
      
        # cut the name in half
        half = current.stem[:len(current.stem)//2]     
      
        # get path for two directories above 
        base = current.parent.parent.parent         
        num = 1      # number to add to filename so to avoid duplicates
      
        # check for files with the same name
        while os.path.exists(base / (half + str(num) + current.suffix)): num += 1                                  
   
        # move the file up two levels and change filename
        shutil.move(current, base / (half + str(num) + current.suffix))  
    
    elif current.is_dir():    # if current is a directory
    
        # iterate and recurse each item in the current directory
        for item in current.iterdir(): traverse(item)        
    
        # if the resulting directory is empty delete it
        if not len(os.listdir(current)): shutil.rmtree(current)  

basedirs = ["Very large directory name1", "Very large directory name2"]

for folder in basedirs:    # iterate folder list
    path = Path(folder) 
    traverse(path)         # traverse the directory
    num = 1
    newpath = path.name[:len(path.name) // 2] #cut directory name in half
    while os.path.exists(path.parent / (newpath + str(num))): num += 1
    shutil.move(folder, path.parent / (newpath + str(num)))  # rename directory
Related