d
Amit DhamuSoftware Engineer
 

Flatten a directory

4 minute read 00000 views

Directory to flatten

/Users/amit/my-folder
  ├── folder1
  │   ├── 1.jpg
  │   ├── 2.jpg
  │   ├── 3.jpg
  │   ├── 4.jpg
  │   ├── 5.jpg
  │   ├── 6.jpg
  │   ├── 7.png
  │   ├── 8.jpg
  │   └── 9.jpg
  ├── folder2
  │   ├── 1.gif
  │   ├── 2.jpg
  │   ├── 3.jpg
  │   ├── 4.jpg
  │   └── 5.jpg
  └── folder3
      ├── 1.jpg
      ├── 2.jpg
      ├── 3.jpg
      └── 4.jpg

The immediate concern we have with flattening the directory tree above is that we will have clashes with filenames so we need to write something that can handle that.

Flatten function

The function below will flatten a multi-level directory and move all files to the root directory deleting all sub-folders in the process. Any files with the same name will have a count appended to their filename. Eg. 1_1.jpg.

import os
import shutil


def flatten(directory):
    for dirpath, _, filenames in os.walk(directory, topdown=False):
        for filename in filenames:
            i = 0
            source = os.path.join(dirpath, filename)
            target = os.path.join(directory, filename)

            while os.path.exists(target):
                i += 1
                file_parts = os.path.splitext(os.path.basename(filename))

                target = os.path.join(
                    directory,
                    file_parts[0] + "_" + str(i) + file_parts[1],
                )

            shutil.move(source, target)

            print("Moved ", source, " to ", target)

        if dirpath != directory:
            os.rmdir(dirpath)

            print("Deleted ", dirpath)

Usage

flatten(os.path.dirname("/Users/amit/my-folder"))

Result

/Users/amit/my-folder
  ├── 1.gif
  ├── 1.jpg
  ├── 1_1.jpg
  ├── 2.jpg
  ├── 2_1.jpg
  ├── 2_2.jpg
  ├── 3.jpg
  ├── 3_1.jpg
  ├── 3_2.jpg
  ├── 4.jpg
  ├── 4_1.jpg
  ├── 4_2.jpg
  ├── 5.jpg
  ├── 5_1.jpg
  ├── 6.jpg
  ├── 7.png
  ├── 8.jpg
  └── 9.jpg