How do I use os.scandir() to return DirEntry objects recursively on a directory tree?
Question:
Python 3.5’s os.scandir(path)
function returns lightweight DirEntry objects that are very helpful with information about files. However, it only works for the immediate path handed to it. Is there a way to wrap it in a recursive function so that it visits all subdirectories beneath the given path?
Answers:
You can scan recursively using os.walk()
, or if you need DirEntry
objects or more control, write a recursive function like scantree()
below:
try:
from os import scandir
except ImportError:
from scandir import scandir # use scandir PyPI module on Python < 3.5
def scantree(path):
"""Recursively yield DirEntry objects for given directory."""
for entry in scandir(path):
if entry.is_dir(follow_symlinks=False):
yield from scantree(entry.path) # see below for Python 2.x
else:
yield entry
if __name__ == '__main__':
import sys
for entry in scantree(sys.argv[1] if len(sys.argv) > 1 else '.'):
print(entry.path)
Notes:
- There are a few more examples in PEP 471 and in the os.scandir() docs.
- You can also add various logic in the for loop to skip directories or files starting with
'.'
and that kind of thing.
- You typically want
follow_symlinks=false
on the is_dir()
calls in recursive functions like this, to avoid symlink loops.
-
On Python 2.x, replace the yield from
line with:
for entry in scantree(entry.path):
yield entry
Python 3.5’s os.scandir(path)
function returns lightweight DirEntry objects that are very helpful with information about files. However, it only works for the immediate path handed to it. Is there a way to wrap it in a recursive function so that it visits all subdirectories beneath the given path?
You can scan recursively using os.walk()
, or if you need DirEntry
objects or more control, write a recursive function like scantree()
below:
try:
from os import scandir
except ImportError:
from scandir import scandir # use scandir PyPI module on Python < 3.5
def scantree(path):
"""Recursively yield DirEntry objects for given directory."""
for entry in scandir(path):
if entry.is_dir(follow_symlinks=False):
yield from scantree(entry.path) # see below for Python 2.x
else:
yield entry
if __name__ == '__main__':
import sys
for entry in scantree(sys.argv[1] if len(sys.argv) > 1 else '.'):
print(entry.path)
Notes:
- There are a few more examples in PEP 471 and in the os.scandir() docs.
- You can also add various logic in the for loop to skip directories or files starting with
'.'
and that kind of thing. - You typically want
follow_symlinks=false
on theis_dir()
calls in recursive functions like this, to avoid symlink loops. -
On Python 2.x, replace the
yield from
line with:for entry in scantree(entry.path): yield entry