Ben Kailon
Ben Kailon

Reputation: 303

os.walk but with directories on top?

I have some simple code to print out the structure of a directory. My example directory ABC contains subdirectory A containing A.txt, a subdirectory Z containing Z.txt, and a file info.txt. In real use, this will be big collection of many files and nested directories.

import os
topdir = 'ABC/'
for dirpath, dirnames, files in os.walk(topdir):
    print(os.path.join(dirpath))
    for name in files:
        print(os.path.join(dirpath, name))

The output is:

ABC/
ABC/info.txt
ABC/A
ABC/A/A.txt
ABC/Z
ABC/Z/Z.txt

How can I make it so directories are processed/printed on the top? I want the output to replicate what I see in Windows Explorer, which displays directories first, and files after.

The output I want:

ABC/
ABC/A
ABC/A/A.txt
ABC/Z
ABC/Z/Z.txt
ABC/info.txt

Upvotes: 3

Views: 151

Answers (1)

tobias_k
tobias_k

Reputation: 82949

Without storing all the files in a list and sorting that list in one way or the other, you could make a recursive function and first recurse to the next level of the directory structure before printing the files on the current level:

def print_dirs(directories):
    try:
        dirpath, dirnames, files = next(directories)
        print(dirpath)              # print current path; no need for join here
        for _ in dirnames:          # once for each sub-directory...
            print_dirs(directories) # ... recursively call generator
        for name in files:          # now, print files in current directory
            print(os.path.join(dirpath, name))
    except StopIteration:
        pass

print_dirs(os.walk(topdir))

The same could also be done with a stack, but I think this way it's a little bit clearer. And yes, this will also store some directories in a list/on a stack, but not all the files but just as many as there are levels of nested directories.

Edit: This had a problem of printing any next directory on the generator, even if that's not a sub-directory but a sibling (or "uncle" or whatever). The for _ in dirnames loop should fix that, making the recursive call once for each of the subdirectories, if any. The directory itself does not have to be passed as a parameter as it will be gotten from the generator.

Upvotes: 3

Related Questions