Hello there,
Is there a way to search for a file everywhere in the SD card with micropython(pycom to be specific)?
In my application there is config.json file. And a want to provide a feature where if the config file is not where it should be, then the sytem ask the and user to search for it other places.
I think I can do some recursive algorithm with os.listdir() but I am wondering is there a more elegant and optimal way?
Thanks in advance!
searchig for a file in sd
Re: searchig for a file in sd
The os.walk function from python is implemented for the unix version MicroPython over here: https://github.com/micropython/micropyt ... #L147-L163
It probably needs a few tweaks to make it work on embedded MicroPython. os.walk behaves like a generator so you can enumerate all of the files with a single for loop. The documentation for os.walk is here: https://docs.python.org/2/library/os.html#os.walk
You could also use a customized version to do exactly what you want with less code.
It probably needs a few tweaks to make it work on embedded MicroPython. os.walk behaves like a generator so you can enumerate all of the files with a single for loop. The documentation for os.walk is here: https://docs.python.org/2/library/os.html#os.walk
You could also use a customized version to do exactly what you want with less code.
Re: searchig for a file in sd
Manually is all I know about...
Code: Select all
import os
def merge(*args):
r = ''
slash = '/'
for part in args:
r += (slash + part)
r = r.replace(3 * slash, slash)
r = r.replace(2 * slash, slash)
if r != slash and r[-1] == slash:
r = r[:-1]
return r
def find(target_file, path='/', recurse=False):
# create list of files
file_list = list(os.ilistdir(path))
# only recurse through the dirs if needed
if recurse:
for f in file_list:
if f[1] == 16384:
find(target_file, merge(path, f[0]), recurse)
# scan the files
for f in file_list:
if f[1] == 32768:
if f[0] == target_file:
hit = merge(path, f[0])
print(hit)
#find('__init__.py', '/', True)
-
- Posts: 463
- Joined: Wed Apr 08, 2015 5:19 am
Re: searchig for a file in sd
Using os.ilistdir() only to convert the return value to a list isn't very effective and can lead to memory errors when searching directories with many entries.
Here's my version of a find function, which acts as an iterator, i.e. yields matching files (with full path) one by one. It recurses by default. If there's a deeply nested directory structure beneath the starting directory it may therefor hit the recursion limit of MicroPython. But I think that's highly unlikely when used on a microprocessor board flash filesystem and a non-recursive solution would probably run into a memory error much faster. Anyway, if you're concerned, that the recursion limit may be hit, just wrap the call in a try/except RuntimeError.
Example usage:
Here's my version of a find function, which acts as an iterator, i.e. yields matching files (with full path) one by one. It recurses by default. If there's a deeply nested directory structure beneath the starting directory it may therefor hit the recursion limit of MicroPython. But I think that's highly unlikely when used on a microprocessor board flash filesystem and a non-recursive solution would probably run into a memory error much faster. Anyway, if you're concerned, that the recursion limit may be hit, just wrap the call in a try/except RuntimeError.
Code: Select all
import os
from micropython import const
STAT_DIR = const(0x4000)
def pathjoin(*parts):
path = []
for part in parts:
part = part.rstrip("/")
if part.startswith("/"):
path = [part]
else:
path.append(part)
return "/".join(path)
def find(filename, path="/", recurse=True):
for name, type_, *_ in os.ilistdir(path):
# unix port includes these:
if name in ('.', '..'):
continue
# only recurse through the dirs if needed
if recurse and type_ & STAT_DIR:
yield from find(filename, pathjoin(path, name), recurse)
# check the file
elif name == filename:
yield pathjoin(path, name)
Code: Select all
try:
for name in find('main.py', '/flash'):
print(name)
except RuntimeError:
print("Too many levels of sub-directories.")
Re: searchig for a file in sd
Thank you!
SpotlightKid wrote: ↑Tue May 19, 2020 12:19 pmUsing os.ilistdir() only to convert the return value to a list isn't very effective and can lead to memory errors when searching directories with many entries.
Here's my version of a find function, which acts as an iterator, i.e. yields matching files (with full path) one by one. It recurses by default. If there's a deeply nested directory structure beneath the starting directory it may therefor hit the recursion limit of MicroPython. But I think that's highly unlikely when used on a microprocessor board flash filesystem and a non-recursive solution would probably run into a memory error much faster. Anyway, if you're concerned, that the recursion limit may be hit, just wrap the call in a try/except RuntimeError.
Example usage:Code: Select all
import os from micropython import const STAT_DIR = const(0x4000) def pathjoin(*parts): path = [] for part in parts: part = part.rstrip("/") if part.startswith("/"): path = [part] else: path.append(part) return "/".join(path) def find(filename, path="/", recurse=True): for name, type_, *_ in os.ilistdir(path): # unix port includes these: if name in ('.', '..'): continue # only recurse through the dirs if needed if recurse and type_ & STAT_DIR: yield from find(filename, pathjoin(path, name), recurse) # check the file elif name == filename: yield pathjoin(path, name)
Code: Select all
try: for name in find('main.py', '/flash'): print(name) except RuntimeError: print("Too many levels of sub-directories.")