Search code examples
esp32micropython

Trying to traverse (walk) the directory of an esp32 using Micropython


```
# try.py
import uos
dir = 16384

def walk(t): # recursive function
    print('-',t)
    w = uos.ilistdir(t)
    for x in w:
        L = list(x)
        print(L[0], L[1], L[3])
        if L[1] == dir:
            walk(L[0])
        else:
            return
    

z = uos.ilistdir()
for x in z:
    L = list(x)
    print(L[0], L[1], L[3])
    if L[1] == dir:
        walk(L[0])

```

The code stops with an error on line 7, with an error:

Output:

Traverse.py 32768 773

boot.py 32768 139

lib 16384 0

-lib

one 16384 0

-one

Traceback (most recent call last):

File "stdin", line 21, in

File "stdi>", line 12, in walk

File "<tdin", line 7, in walk

OSError: [Errno 2] ENOENT

The directory structure is:

lib

one

    two

        three

    three.py

boot.py

main.py

one.py

Traverse.py

It seems that it stops on a directory that has no files in it


Solution

  • Don't have an ESP to test, but there are some problems here:

    • you shouldn't return if the entry is a file but instead continue, this is why it stops too soon
    • you should skip the current and parent directory to avoid infinite recursion
    • when recursing you have to prepend the top directory, that is probably the reason for the error i.e. your code calls walk('two') but there is no such directory, it has to be one/two)
    • you can use the walk function on the current directory so that last bit where you duplicate the implementation isn't needed.

    Additionally:

    • iterating ilistdir returns tuples which can be indexed as well so no need to convert it into a list
    • and passing collections to print directly also works, no need for separate print(x[0], x[1], ...)

    Adpatation, with slightly different printing of full paths so it's easier to follow:

    import uos
    
    dir_code = 16384
    
    def walk(t):
        print('-', t)
        for x in uos.ilistdir(t):
            print(x)
            if x[1] == dir_code and x[0] != '.' and x[0] != '..':
                walk(t + '/' + x[0])
        
    walk('.')
    

    This will still print directories twice, add all that indexing makes things hard to read. Adaptation with tuple unpacking and printing directories once:

    import uos
    
    dir_code = 16384
    
    def walk(top):
        print(top)
        for name, code, _ in uos.ilistdir(top):
            if code != dir_code:
                print(top + '/' + name)
            elif name not in ('.', '..'):
                walk(top + '/' + name)
        
    walk('.')