0

Is it possible using Python (or some kind of lib) to generate an ascii based tree structure of a directory and all its subdirectories + files?

I've tried a bunch of thing but unfortunately I have not been able to solve this problem.

An example of the output would look something like this:

[rootdir]
|
+--- [subdir0]
|
+--- [subdir1]
|     |
|     +--- file1
|     +--- file2
|
+--- [subdir2]
|     |
|     +--- [subdir3]
|     |
|     +--- [subdir4]
|           |
|           +--- [subdir5]
|                 |
|                 +--- [subdir6]
|                 |     |
|                 |     +--- file4
|                 |
|                 +--- file3
+--- file5
+--- file6

Edit:

My current (aweful) script was requested.

def treeStructure(startpath):

    for root, dirs, files in os.walk(startpath):
        level = root.replace(startpath, '').count(os.sep)
        indent = ' ' * 2 * (level)
        print('{}|'.format(indent[:]))
        print('{}+{}/'.format(indent, os.path.basename(root)))
        subindent = ' ' * 2 * (level + 1)

        for f in files:
            print('{}| +--- {}'.format(subindent[:-2], f))
Nectar
  • 73
  • 2
  • 8
  • This sounds somewhat like an assignment, can we see what you've tried? – Dylan Lawrence Jan 14 '14 at 14:46
  • Why would this be an assignment exactly? I generate a list of paths automatically, which I then convert into structured folders + files for the user to use. I'll post what I wrote once I get off work. – Nectar Jan 14 '14 at 15:58
  • it sounds a bit like a class assignment for a data structures. I meant no offense. – Dylan Lawrence Jan 14 '14 at 17:58
  • The biggest problem I see, is that you're not using recursion. While a loop will work, recursion is the way to go for this. Anytime we find a subdirectory, we recurse, if no subdirectories exist, we print and jump up. If all subdirectories of a directory have been explored, we print our self and move on. – Dylan Lawrence Jan 15 '14 at 13:04

3 Answers3

5

There is a utility called tree on Linux which already does this.

You can also checkout this Python snippet for generating ASCII trees.

arocks
  • 2,862
  • 1
  • 12
  • 20
  • I'm quite aware of the fact that there is a "tree" utility on Linux and even on Windows. That's not what I asked though. – Nectar Jan 14 '14 at 15:56
0

I know it's

Shitty Programming

code but it works. ;)

Here you:

import os

# start point
startpath = '.'

folders = []    # folder store
tuples = []     # folders, subdirs, files


def folder_tree(line, dir):
    one = '|-> V '
    padding = '|   '

    if line == dir:
        # print('V '+line)
        return ('V '+line)

    if line.count(os.sep) == 1:
        line = line.split(os.sep)
        line[0] = one
        # print(''.join(line))
        return (''.join(line))

    if line.count(os.sep) >= 2:
        line = line.split(os.sep)
        line[-2] = one
        for i in range(len(line[:-2])):
            line[i] = padding
        # print(''.join(line))
        return (''.join(line))


def files_tree(dir, *args):
    """

    :param dir: startpath
    :param args: args[0] > tuples, args[1] > folders
    :return: None
    """
    file = '|-> '
    padding = '|   '
    last_file = ''
    tuples = args[0]
    folders_list = args[1]
    for root, subs, files in tuples:
        # no files no worries, skip
        if not files:
            continue

        # will use for padding: padding * sep
        sep = root.count(os.sep)

        # only if root has some files
        if root == dir:
            last_file = [file+str(x) for x in files]
            continue

        if subs:
            # take last elem in subs,
            # use it as value to find the same in folders_list
            # get index + 1 to insert right after
            index = folders_list.index([x for x in folders_list if x.endswith(subs[-1])][0]) + 1

        else:
            # we need name the last of folder in the root
            # to use it to find index
            folder_name = root.split(os.sep)[-1]
            index = folders_list.index([x for x in folders_list if x.endswith(folder_name)][0]) + 1

        # prepare files
        files = [sep * padding + file + x for x in files]

        # now insert files to list
        for i, a in enumerate(range(index, index+len(files))):
            folders_list.insert(a, files[i])

    if last_file:
        # merge files in root dir
        folders_list = folders_list + last_file

    # final print tree
    for elm in folders_list:
        print(elm)


def tree_walk(dir):
    for folder, subs, files in os.walk(dir):
        tuples.append((folder, subs, files))
        folders.append(folder_tree(folder, dir))


tree_walk(startpath)
folder_tree(tuples, startpath)
files_tree(startpath, tuples, folders)

And here is result:

V .
|-> V folder1
|   |-> V folder2
|   |   |-> V folder3
|   |   |   |-> file3.txt
|   |   |-> file2.txt
|   |-> V folderX
|   |-> file1.txt
|-> 02-hw1_wdwwfm.py
|-> 06-t1-home1.py
|-> 06-t1-home2.py
|-> hw1.py
Igor Z
  • 601
  • 6
  • 7
0

This is another

Weird Programming

But I think that this work as your criteria, the code is here:

import os

path_dir = r'E:\rootdir'

def list_files(startpath):
    for root, dirs, files in os.walk(startpath):
        dir_prefix = []
        dir_content = []
        for dir in dirs:
            go_inside = os.path.join(startpath, dir)
            dir_prefix.append('')
            dir_content.append(list_files(go_inside))
        files_lst = []
        files_prefix = []
        for f in files:
            files_lst.append(f)
            files_prefix.append('')
        return {'name': root, 'files': files_lst, 'file_ext': files_prefix, 'dirs': dir_content, 'dir_ext': dir_prefix}

result = list_files(path_dir)

def prepend(list, str):
    list = ['{}{}'.format(i,str) for i in list]
    return(list)

def add_string(reslt, str_test):
    if reslt['file_ext']!=[]:
        reslt['file_ext']=prepend(reslt['file_ext'],str_test)
    if reslt['dirs']!=[]:
        reslt['dir_ext']=prepend(reslt['dir_ext'],str_test)
        for i in range(len(reslt['dirs'])):
            add_string(reslt['dirs'][i],str_test)

def print_dir(reslt):
    #prefix
    space = '     '
    branch = '|    '
    #pointer
    tee = '+--- '
    #Resulting Root Folder
    if(reslt['name']==path_dir):
        print ('['+path_dir+']\n|')
    else:
        print(reslt['name'])
    #Resulting List of Folder first
    if reslt['dirs']!=[]:
        for i in range(len(reslt['dirs'])):
            if (reslt['files']==[]) and (reslt['dirs'][i] == reslt['dirs'][len(reslt['dirs'])-1]):
                add_string(reslt['dirs'][i], space)
                below_dir = space+branch
            else:
                add_string(reslt['dirs'][i], branch)
                below_dir = branch+branch
            reslt['dirs'][i]['name'] = reslt['dir_ext'][i]+tee+'['+os.path.basename(reslt['dirs'][i]['name'])+']\n'+reslt['dir_ext'][i]+below_dir
            print_dir(reslt['dirs'][i])
    #Resulting List of Files
    if reslt['files']!=[]:
        for i in range(len(reslt['files'])):
            reslt['files'][i] = reslt['file_ext'][i] + tee + reslt['files'][i]            
            print(reslt['files'][i])

print_dir(result)

and the result is here:

[E:\rootdir]
|
+--- [subdir1]
|    |    
|    +--- file1
|    +--- file2
+--- [subdir2]
|    |    
|    +--- [subdir3]
|    |    |    
|    +--- [subdir4]
|         |    
|         +--- [subdir5]
|              |    
|              +--- [subdir6]
|              |    |    
|              |    +--- file4
|              +--- file3
+--- file5
+--- file6

This is improvement from this answer https://stackoverflow.com/a/57356704/10733973, hope it will help you even though it is much late.

D. Shadow
  • 1
  • 3