¿Cómo enumero todos los archivos de un directorio?

3467

¿Cómo puedo enumerar todos los archivos de un directorio en Python y agregarlos a list?

1
5303

os.listdir()obtendrá todo lo que está en un directorio: archivos y directorios .

Si solo desea archivos, puede filtrar esto usando os.path:

from os import listdir
from os.path import isfile, join
onlyfiles = [f for f in listdir(mypath) if isfile(join(mypath, f))]

o se puede usar os.walk()lo que dió dos listas para cada directorio visitas it - división en archivos y directorios para usted. Si solo desea el directorio superior, puede romper la primera vez que cede

from os import walk

f = []
for (dirpath, dirnames, filenames) in walk(mypath):
    f.extend(filenames)
    break

o, más corto:

from os import walk

filenames = next(walk(mypath), (None, None, []))[2]  # [] if no file
8
  • 112
    Un poco más simple: (_, _, filenames) = walk(mypath).next() (si está seguro de que la caminata devolverá al menos un valor, que debería)misterbee 14/07/2013 a las 20:56
  • 10
    Ligera modificación para almacenar rutas completas: para (ruta de directorio, nombres de directorio, nombres de archivo) en os.walk (mypath): checksum_files.extend (os.path.join (dirpath, nombre de archivo) para nombre de archivo en nombres de archivo) breakokigan 23 de septiembre de 2013 a las 21:31
  • 176
    f.extend(filenames)en realidad no es equivalente a f = f + filenames. extendmodificará fen el lugar, mientras que agregar crea una nueva lista en una nueva ubicación de memoria. Este medio extendes generalmente más eficiente que +, pero a veces puede generar confusión si varios objetos contienen referencias a la lista. Por último, vale la pena señalar que f += filenameses equivalente a f.extend(filenames), no f = f + filenames . Benjamin Hodgson 22/10/2013 a las 8:55
  • 35
    @misterbee, su solución es la mejor, solo una pequeña mejora:_, _, filenames = next(walk(mypath), (None, None, []))bgusach 5 de marzo de 2015 a las 7:36
  • 2
    f += filenameses equivalente a extender y no al revés ??? Dios. Umagon 12 jul.20 a las 9:18
2076

Prefiero usar el globmódulo, ya que hace coincidir y expandir patrones.

import glob
print(glob.glob("/home/adam/*"))

Hace coincidir patrones de forma intuitiva

import glob
# All files ending with .txt
print(glob.glob("/home/adam/*.txt")) 
# All files ending with .txt with depth of 2 folder
print(glob.glob("/home/adam/*/*.txt")) 

Devolverá una lista con los archivos consultados:

['/home/adam/file1.txt', '/home/adam/file2.txt', .... ]
5
  • 19
    ese es un atajo para listdir + fnmatch docs.python.org/library/fnmatch.html#fnmatch.fnmatchStefano 1 de julio de 2011 a las 13:03
  • 48
    para aclarar, esto no devuelve la "ruta completa"; simplemente devuelve la expansión del globo, cualquiera que sea. Por ejemplo, dado /home/user/foo/bar/hello.txt, entonces, si se ejecuta en un directorio foo, glob("bar/*.txt")volverá bar/hello.txt. Hay casos en los que de hecho desea la ruta completa (es decir, absoluta); para esos casos, consulte stackoverflow.com/questions/51520/…michael 16 de agosto de 2016 a las 12:07
  • 1
    Relacionado: busque archivos de forma recursiva con glob: stackoverflow.com/a/2186565/4561887Gabriel Staples 3 de septiembre de 2018 a las 3:25
  • 8
    no responde a esta pregunta. glob.glob("*")haría. Jean-François Fabre 17 de mayo de 19 a las 18:36
  • ¿Hay alguna forma de garantizar que los elementos devueltos por glob sean solo archivos? Pregunto sobre la instancia en la que los archivos podrían existir sin extensiones (u otros escenarios en los que los archivos y carpetas no se pueden distinguir simplemente de sus cadenas de ruta). Observo que esta es una aclaración apropiada aquí, ya que el OP no especificó si sus archivos tienen extensiones. aamailhot 11 de agosto a las 21:57
1265

os.listdir() - list in the current directory

Con listdir en el módulo del sistema operativo, obtienes los archivos y las carpetas en el directorio actual

 import os
 arr = os.listdir()
 print(arr)
 
 >>> ['$RECYCLE.BIN', 'work.txt', '3ebooks.txt', 'documents']

Buscando en un directorio

arr = os.listdir('c:\\files')

glob from glob

con glob puede especificar un tipo de archivo para listar como este

import glob

txtfiles = []
for file in glob.glob("*.txt"):
    txtfiles.append(file)

glob en una lista de comprensión

mylist = [f for f in glob.glob("*.txt")]

obtener la ruta completa de solo los archivos en el directorio actual

import os
from os import listdir
from os.path import isfile, join

cwd = os.getcwd()
onlyfiles = [os.path.join(cwd, f) for f in os.listdir(cwd) if 
os.path.isfile(os.path.join(cwd, f))]
print(onlyfiles) 

['G:\\getfilesname\\getfilesname.py', 'G:\\getfilesname\\example.txt']

Getting the full path name with os.path.abspath

Obtienes el camino completo a cambio

 import os
 files_path = [os.path.abspath(x) for x in os.listdir()]
 print(files_path)
 
 ['F:\\documenti\applications.txt', 'F:\\documenti\collections.txt']

Walk: going through sub directories

os.walk devuelve la raíz, la lista de directorios y la lista de archivos, por eso los descomprimí en r, d, f en el bucle for; luego, busca otros archivos y directorios en las subcarpetas de la raíz y así sucesivamente hasta que no haya subcarpetas.

import os

# Getting the current work directory (cwd)
thisdir = os.getcwd()

# r=root, d=directories, f = files
for r, d, f in os.walk(thisdir):
    for file in f:
        if file.endswith(".docx"):
            print(os.path.join(r, file))

os.listdir(): get files in the current directory (Python 2)

En Python 2, si desea la lista de archivos en el directorio actual, debe dar el argumento como '.' u os.getcwd () en el método os.listdir.

 import os
 arr = os.listdir('.')
 print(arr)
 
 >>> ['$RECYCLE.BIN', 'work.txt', '3ebooks.txt', 'documents']

To go up in the directory tree

# Method 1
x = os.listdir('..')

# Method 2
x= os.listdir('/')

Get files: os.listdir() in a particular directory (Python 2 and 3)

 import os
 arr = os.listdir('F:\\python')
 print(arr)
 
 >>> ['$RECYCLE.BIN', 'work.txt', '3ebooks.txt', 'documents']

Get files of a particular subdirectory with os.listdir()

import os

x = os.listdir("./content")

os.walk('.') - current directory

 import os
 arr = next(os.walk('.'))[2]
 print(arr)
 
 >>> ['5bs_Turismo1.pdf', '5bs_Turismo1.pptx', 'esperienza.txt']

next(os.walk('.')) and os.path.join('dir', 'file')

 import os
 arr = []
 for d,r,f in next(os.walk("F:\\_python")):
     for file in f:
         arr.append(os.path.join(r,file))

 for f in arr:
     print(files)

>>> F:\\_python\\dict_class.py
>>> F:\\_python\\programmi.txt

next(os.walk('F:\\') - get the full path - list comprehension

 [os.path.join(r,file) for r,d,f in next(os.walk("F:\\_python")) for file in f]
 
 >>> ['F:\\_python\\dict_class.py', 'F:\\_python\\programmi.txt']

os.walk - get full path - all files in sub dirs**

x = [os.path.join(r,file) for r,d,f in os.walk("F:\\_python") for file in f]
print(x)

>>> ['F:\\_python\\dict.py', 'F:\\_python\\progr.txt', 'F:\\_python\\readl.py']

os.listdir() - get only txt files

 arr_txt = [x for x in os.listdir() if x.endswith(".txt")]
 print(arr_txt)
 
 >>> ['work.txt', '3ebooks.txt']

Using glob to get the full path of the files

Si necesito la ruta absoluta de los archivos:

from path import path
from glob import glob
x = [path(f).abspath() for f in glob("F:\\*.txt")]
for f in x:
    print(f)

>>> F:\acquistionline.txt
>>> F:\acquisti_2018.txt
>>> F:\bootstrap_jquery_ecc.txt

Using os.path.isfile to avoid directories in the list

import os.path
listOfFiles = [f for f in os.listdir() if os.path.isfile(f)]
print(listOfFiles)

>>> ['a simple game.py', 'data.txt', 'decorator.py']

Using pathlib from Python 3.4

import pathlib

flist = []
for p in pathlib.Path('.').iterdir():
    if p.is_file():
        print(p)
        flist.append(p)

 >>> error.PNG
 >>> exemaker.bat
 >>> guiprova.mp3
 >>> setup.py
 >>> speak_gui2.py
 >>> thumb.PNG

Con list comprehension:

flist = [p for p in pathlib.Path('.').iterdir() if p.is_file()]

Alternativamente, use en pathlib.Path()lugar depathlib.Path(".")

Use glob method in pathlib.Path()

import pathlib

py = pathlib.Path().glob("*.py")
for file in py:
    print(file)

>>> stack_overflow_list.py
>>> stack_overflow_list_tkinter.py

Get all and only files with os.walk

import os
x = [i[2] for i in os.walk('.')]
y=[]
for t in x:
    for f in t:
        y.append(f)
print(y)

>>> ['append_to_list.py', 'data.txt', 'data1.txt', 'data2.txt', 'data_180617', 'os_walk.py', 'READ2.py', 'read_data.py', 'somma_defaltdic.py', 'substitute_words.py', 'sum_data.py', 'data.txt', 'data1.txt', 'data_180617']

Get only files with next and walk in a directory

 import os
 x = next(os.walk('F://python'))[2]
 print(x)
 
 >>> ['calculator.bat','calculator.py']

Get only directories with next and walk in a directory

 import os
 next(os.walk('F://python'))[1] # for the current dir use ('.')
 
 >>> ['python3','others']

Get all the subdir names with walk

for r,d,f in os.walk("F:\\_python"):
    for dirs in d:
        print(dirs)

>>> .vscode
>>> pyexcel
>>> pyschool.py
>>> subtitles
>>> _metaprogramming
>>> .ipynb_checkpoints

os.scandir() from Python 3.5 and greater

import os
x = [f.name for f in os.scandir() if f.is_file()]
print(x)

>>> ['calculator.bat','calculator.py']

# Another example with scandir (a little variation from docs.python.org)
# This one is more efficient than os.listdir.
# In this case, it shows the files only in the current directory
# where the script is executed.

import os
with os.scandir() as i:
    for entry in i:
        if entry.is_file():
            print(entry.name)

>>> ebookmaker.py
>>> error.PNG
>>> exemaker.bat
>>> guiprova.mp3
>>> setup.py
>>> speakgui4.py
>>> speak_gui2.py
>>> speak_gui3.py
>>> thumb.PNG

Examples:

Ex. 1: How many files are there in the subdirectories?

En este ejemplo, buscamos la cantidad de archivos que están incluidos en todo el directorio y sus subdirectorios.

import os

def count(dir, counter=0):
    "returns number of files in dir and subdirs"
    for pack in os.walk(dir):
        for f in pack[2]:
            counter += 1
    return dir + " : " + str(counter) + "files"

print(count("F:\\python"))

>>> 'F:\\\python' : 12057 files'

Ex.2: How to copy all files from a directory to another?

Un script para ordenar en su computadora la búsqueda de todos los archivos de un tipo (predeterminado: pptx) y copiarlos en una nueva carpeta.

import os
import shutil
from path import path

destination = "F:\\file_copied"
# os.makedirs(destination)

def copyfile(dir, filetype='pptx', counter=0):
    "Searches for pptx (or other - pptx is the default) files and copies them"
    for pack in os.walk(dir):
        for f in pack[2]:
            if f.endswith(filetype):
                fullpath = pack[0] + "\\" + f
                print(fullpath)
                shutil.copy(fullpath, destination)
                counter += 1
    if counter > 0:
        print('-' * 30)
        print("\t==> Found in: `" + dir + "` : " + str(counter) + " files\n")

for dir in os.listdir():
    "searches for folders that starts with `_`"
    if dir[0] == '_':
        # copyfile(dir, filetype='pdf')
        copyfile(dir, filetype='txt')


>>> _compiti18\Compito Contabilità 1\conti.txt
>>> _compiti18\Compito Contabilità 1\modula4.txt
>>> _compiti18\Compito Contabilità 1\moduloa4.txt
>>> ------------------------
>>> ==> Found in: `_compiti18` : 3 files

Ex. 3: How to get all the files in a txt file

En caso de que desee crear un archivo txt con todos los nombres de archivo:

import os
mylist = ""
with open("filelist.txt", "w", encoding="utf-8") as file:
    for eachfile in os.listdir():
        mylist += eachfile + "\n"
    file.write(mylist)

Example: txt with all the files of an hard drive

"""
We are going to save a txt file with all the files in your directory.
We will use the function walk()
"""

import os

# see all the methods of os
# print(*dir(os), sep=", ")
listafile = []
percorso = []
with open("lista_file.txt", "w", encoding='utf-8') as testo:
    for root, dirs, files in os.walk("D:\\"):
        for file in files:
            listafile.append(file)
            percorso.append(root + "\\" + file)
            testo.write(file + "\n")
listafile.sort()
print("N. of files", len(listafile))
with open("lista_file_ordinata.txt", "w", encoding="utf-8") as testo_ordinato:
    for file in listafile:
        testo_ordinato.write(file + "\n")

with open("percorso.txt", "w", encoding="utf-8") as file_percorso:
    for file in percorso:
        file_percorso.write(file + "\n")

os.system("lista_file.txt")
os.system("lista_file_ordinata.txt")
os.system("percorso.txt")

All the file of C:\ in one text file

Esta es una versión más corta del código anterior. Cambie la carpeta donde comenzar a buscar los archivos si necesita comenzar desde otra posición. Este código genera un archivo de texto de 50 mb en mi computadora con algo menos de 500.000 líneas con archivos con la ruta completa.

import os

with open("file.txt", "w", encoding="utf-8") as filewrite:
    for r, d, f in os.walk("C:\\"):
        for file in f:
            filewrite.write(f"{r + file}\n")

How to write a file with all paths in a folder of a type

Con esta función puedes crear un archivo txt que tendrá el nombre de un tipo de archivo que busques (ej. Pngfile.txt) con toda la ruta completa de todos los archivos de ese tipo. A veces puede ser útil, creo.

import os

def searchfiles(extension='.ttf', folder='H:\\'):
    "Create a txt file with all the file of a type"
    with open(extension[1:] + "file.txt", "w", encoding="utf-8") as filewrite:
        for r, d, f in os.walk(folder):
            for file in f:
                if file.endswith(extension):
                    filewrite.write(f"{r + file}\n")

# looking for png file (fonts) in the hard disk H:\
searchfiles('.png', 'H:\\')

>>> H:\4bs_18\Dolphins5.png
>>> H:\4bs_18\Dolphins6.png
>>> H:\4bs_18\Dolphins7.png
>>> H:\5_18\marketing html\assets\imageslogo2.png
>>> H:\7z001.png
>>> H:\7z002.png

(New) Find all files and open them with tkinter GUI

Solo quería agregar en este 2019 una pequeña aplicación para buscar todos los archivos en un directorio y poder abrirlos haciendo doble clic en el nombre del archivo en la lista. ingrese la descripción de la imagen aquí

import tkinter as tk
import os

def searchfiles(extension='.txt', folder='H:\\'):
    "insert all files in the listbox"
    for r, d, f in os.walk(folder):
        for file in f:
            if file.endswith(extension):
                lb.insert(0, r + "\\" + file)

def open_file():
    os.startfile(lb.get(lb.curselection()[0]))

root = tk.Tk()
root.geometry("400x400")
bt = tk.Button(root, text="Search", command=lambda:searchfiles('.png', 'H:\\'))
bt.pack()
lb = tk.Listbox(root)
lb.pack(fill="both", expand=1)
lb.bind("<Double-Button>", lambda x: open_file())
root.mainloop()
8
  • sesenta y cinco
    Esta es una mezcla de demasiadas respuestas a preguntas que no se hacen aquí. También puede valer la pena explicar cuáles son las advertencias o los enfoques recomendados. No me conviene saber una forma frente a 20 formas de hacer lo mismo, a menos que también sepa cuál es más apropiada para usar y cuándo. cs95 27/01/20 a las 9:27
  • 2
    Ok, lo antes posible voy a echar un vistazo a mi respuesta y tratar de hacerlo más limpio y con más informaciones útiles acerca de la diferencia entre los métodos etc.PythonProgrammi 29/01/20 a las 19:56
  • 1
    No debe determinar la extensión del archivo comprobando si el nombre del archivo contiene una subcadena. Eso podría causar muchos problemas. Recomiendo comprobar siempre si el nombre del archivo termina con la subcadena en particular. ni1ight 2 mar.20 a las 14:38
  • 3
    Estas compilaciones pueden ser útiles, pero esta respuesta en particular no agrega valor a las respuestas existentes. Solo para dar un ejemplo, [f for f in glob.glob("*.txt")]es equivalente glob.glob("*.txt")y no garantiza ninguna sección adicional en este artículo. También es muy prolijo y con mucho espacio. Se podría realizar una mejora agregando explicaciones o señalando diferencias en lugar de enumerar otra variante. Turun Ambartanen 12/10/20 a las 10:20
  • 1
    Gracias por el comentario, tienes razón por supuesto y seguiré tus consejos lo antes posible para que sea más útil, tal vez en estos años pueda hacer mejores respuestas. Solo dame unos días para reelaborarlo. PythonProgrammi 15 oct.20 a las 11:07
917
import os
os.listdir("somedirectory")

devolverá una lista de todos los archivos y directorios en "algún directorio".

2
  • 12
    Esto devuelve la ruta relativa de los archivos, en comparación con la ruta completa devuelta porglob.globxji 17 de mayo de 2016 a las 14:32
  • 24
    @JIXiang: os.listdir()siempre devuelve meros nombres de archivo (no rutas relativas). Lo que glob.glob()devuelve está impulsado por el formato de ruta del patrón de entrada. mklement0 30/11/2016 a las 18:14
176

Una solución de una línea para obtener solo una lista de archivos (sin subdirectorios):

filenames = next(os.walk(path))[2]

o nombres de ruta absolutos:

paths = [os.path.join(path, fn) for fn in next(os.walk(path))[2]]
3
  • 7
    Solo una sola línea si ya lo has hecho import os. glob()Me parece menos conciso que a mí. ArtOfWarfare 28/11/2014 a las 20:22
  • 4
    El problema con glob es que una carpeta llamada 'algo.algo' sería devuelta por glob ('/ home / adam /*.*')Remi 1 dic 2014 a las 9:08
  • 6
    En OS X, hay algo llamado paquete. Es un directorio que generalmente debe tratarse como un archivo (como un .tar). ¿Le gustaría que se tratara como un archivo o un directorio? El uso glob()lo trataría como un archivo. Su método lo trataría como un directorio. ArtOfWarfare 1 de diciembre de 2014 a las 19:44
142

Obtener rutas de archivo completas desde un directorio y todos sus subdirectorios

import os

def get_filepaths(directory):
    """
    This function will generate the file names in a directory 
    tree by walking the tree either top-down or bottom-up. For each 
    directory in the tree rooted at directory top (including top itself), 
    it yields a 3-tuple (dirpath, dirnames, filenames).
    """
    file_paths = []  # List which will store all of the full filepaths.

    # Walk the tree.
    for root, directories, files in os.walk(directory):
        for filename in files:
            # Join the two strings in order to form the full filepath.
            filepath = os.path.join(root, filename)
            file_paths.append(filepath)  # Add it to the list.

    return file_paths  # Self-explanatory.

# Run the above function and store its results in a variable.   
full_file_paths = get_filepaths("/Users/johnny/Desktop/TEST")

  • La ruta que proporcioné en la función anterior contenía 3 archivos, dos de ellos en el directorio raíz y otro en una subcarpeta llamada "SUBFOLDER". Ahora puedes hacer cosas como:
  • print full_file_paths que imprimirá la lista:

    • ['/Users/johnny/Desktop/TEST/file1.txt', '/Users/johnny/Desktop/TEST/file2.txt', '/Users/johnny/Desktop/TEST/SUBFOLDER/file3.dat']

Si lo desea, puede abrir y leer el contenido, o centrarse solo en los archivos con la extensión ".dat" como en el siguiente código:

for f in full_file_paths:
  if f.endswith(".dat"):
    print f

/Users/johnny/Desktop/TEST/SUBFOLDER/file3.dat

0
89

Desde la versión 3.4 hay iteradores incorporados para esto que son mucho más eficientes que os.listdir():

pathlib: Nuevo en la versión 3.4.

>>> import pathlib
>>> [p for p in pathlib.Path('.').iterdir() if p.is_file()]

Según PEP 428 , el objetivo de la pathlibbiblioteca es proporcionar una jerarquía simple de clases para manejar las rutas del sistema de archivos y las operaciones comunes que los usuarios realizan sobre ellas.

os.scandir(): Nuevo en la versión 3.5.

>>> import os
>>> [entry for entry in os.scandir('.') if entry.is_file()]

Tenga en cuenta que se os.walk()usa en os.scandir()lugar de la os.listdir()versión 3.5, y su velocidad se incrementó de 2 a 20 veces según PEP 471 .

Permítanme también recomendar leer el comentario de ShadowRanger a continuación.

4
  • 1
    ¡Gracias! Creo que es la única solución que no devuelve directamente a list. Podría usar en p.namelugar del primero palternativamente si se prefiere. jeromej 22/06/2015 a las 12:36
  • 1
    ¡Bienvenido! Preferiría generar pathlib.Path()instancias ya que tienen muchos métodos útiles que no querría desperdiciar. También puede llamarlos str(p)para obtener nombres de rutas. SzieberthAdam 13/07/2015 a las 14:56
  • 6
    Nota: La os.scandirsolución será más eficiente que os.listdircon una os.path.is_fileverificación o similar, incluso si necesita una list(para que no se beneficie de la iteración perezosa), porque os.scandirutiliza API proporcionadas por el sistema operativo que le brindan la is_fileinformación de forma gratuita a medida que se itera , viaje sin vuelta por archivo en el disco a statellos en absoluto (en Windows, los DirEntrys conseguir que completa statinformación de forma gratuita, en sistemas * NIX que necesita statpara obtener información más allá is_file, is_dir, etc., pero DirEntrycachés en primera statpor conveniencia). ShadowRanger 20/11/15 a las 22:38
  • 1
    También puede usar entry.namepara obtener solo el nombre del archivo o entry.pathpara obtener su ruta completa. No más os.path.join () por todos lados. user136036 28/03/2017 a las 20:26
60

Notas preliminares

  • Aunque hay una clara diferenciación entre los términos de archivo y directorio en el texto de la pregunta, algunos pueden argumentar que los directorios son en realidad archivos especiales.
  • La declaración: " todos los archivos de un directorio " se puede interpretar de dos maneras:
    1. Todos directos (nivel 1) o descendientes sólo se
    2. Todos los descendientes en todo el árbol de directorios (incluidos los de los subdirectorios)
  • Cuando se hizo la pregunta, imagino que Python 2 , era la versión LTS , sin embargo, las muestras de código serán ejecutadas por Python 3 ( .5 ) (las mantendré como compatibles con Python 2 como sea posible; también, cualquier código que pertenezca a Python que voy a publicar es de v3.5.4 , a menos que se especifique lo contrario). Eso tiene consecuencias relacionadas con otra palabra clave en la pregunta: " agréguelos a una lista ":

    • En las versiones anteriores a Python 2.2 , las secuencias (iterables) estaban representadas principalmente por listas (tuplas, conjuntos, ...)
    • En Python 2.2 , se introdujo el concepto de generador ( [Python.Wiki]: Generadores ), cortesía de [Python 3: La declaración de rendimiento ). A medida que pasaba el tiempo, las contrapartes del generador comenzaron a aparecer para funciones que regresaban / trabajaban con listas.
    • En Python 3 , el generador es el comportamiento predeterminado
    • No estoy seguro de si devolver una lista sigue siendo obligatorio (o un generador también lo haría), pero pasar un generador al constructor de la lista creará una lista a partir de ella (y también la consumirá). El siguiente ejemplo ilustra las diferencias en [Python 3]: mapa ( función, iterable, ... )
    >>> import sys
    >>> sys.version
    '2.7.10 (default, Mar  8 2016, 15:02:46) [MSC v.1600 64 bit (AMD64)]'
    >>> m = map(lambda x: x, [1, 2, 3])  # Just a dummy lambda function
    >>> m, type(m)
    ([1, 2, 3], <type 'list'>)
    >>> len(m)
    3
    


    >>> import sys
    >>> sys.version
    '3.5.4 (v3.5.4:3f56838, Aug  8 2017, 02:17:05) [MSC v.1900 64 bit (AMD64)]'
    >>> m = map(lambda x: x, [1, 2, 3])
    >>> m, type(m)
    (<map object at 0x000001B4257342B0>, <class 'map'>)
    >>> len(m)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: object of type 'map' has no len()
    >>> lm0 = list(m)  # Build a list from the generator
    >>> lm0, type(lm0)
    ([1, 2, 3], <class 'list'>)
    >>>
    >>> lm1 = list(m)  # Build a list from the same generator
    >>> lm1, type(lm1)  # Empty list now - generator already consumed
    ([], <class 'list'>)
    
  • Los ejemplos se basarán en un directorio llamado root_dir con la siguiente estructura (este ejemplo es para Win , pero también estoy usando el mismo árbol en Lnx ):

    E:\Work\Dev\StackOverflow\q003207219>tree /f "root_dir"
    Folder PATH listing for volume Work
    Volume serial number is 00000029 3655:6FED
    E:\WORK\DEV\STACKOVERFLOW\Q003207219\ROOT_DIR
    ¦   file0
    ¦   file1
    ¦
    +---dir0
    ¦   +---dir00
    ¦   ¦   ¦   file000
    ¦   ¦   ¦
    ¦   ¦   +---dir000
    ¦   ¦           file0000
    ¦   ¦
    ¦   +---dir01
    ¦   ¦       file010
    ¦   ¦       file011
    ¦   ¦
    ¦   +---dir02
    ¦       +---dir020
    ¦           +---dir0200
    +---dir1
    ¦       file10
    ¦       file11
    ¦       file12
    ¦
    +---dir2
    ¦   ¦   file20
    ¦   ¦
    ¦   +---dir20
    ¦           file200
    ¦
    +---dir3
    


Soluciones

Enfoques programáticos:

  1. [Python 3]: os. listdir ( ruta = '.' )

    Return a list containing the names of the entries in the directory given by path. The list is in arbitrary order, and does not include the special entries '.' and '..' ...


    >>> import os
    >>> root_dir = "root_dir"  # Path relative to current dir (os.getcwd())
    >>>
    >>> os.listdir(root_dir)  # List all the items in root_dir
    ['dir0', 'dir1', 'dir2', 'dir3', 'file0', 'file1']
    >>>
    >>> [item for item in os.listdir(root_dir) if os.path.isfile(os.path.join(root_dir, item))]  # Filter items and only keep files (strip out directories)
    ['file0', 'file1']
    

    Un ejemplo más elaborado ( code_os_listdir.py ):

    import os
    from pprint import pformat
    
    
    def _get_dir_content(path, include_folders, recursive):
        entries = os.listdir(path)
        for entry in entries:
            entry_with_path = os.path.join(path, entry)
            if os.path.isdir(entry_with_path):
                if include_folders:
                    yield entry_with_path
                if recursive:
                    for sub_entry in _get_dir_content(entry_with_path, include_folders, recursive):
                        yield sub_entry
            else:
                yield entry_with_path
    
    
    def get_dir_content(path, include_folders=True, recursive=True, prepend_folder_name=True):
        path_len = len(path) + len(os.path.sep)
        for item in _get_dir_content(path, include_folders, recursive):
            yield item if prepend_folder_name else item[path_len:]
    
    
    def _get_dir_content_old(path, include_folders, recursive):
        entries = os.listdir(path)
        ret = list()
        for entry in entries:
            entry_with_path = os.path.join(path, entry)
            if os.path.isdir(entry_with_path):
                if include_folders:
                    ret.append(entry_with_path)
                if recursive:
                    ret.extend(_get_dir_content_old(entry_with_path, include_folders, recursive))
            else:
                ret.append(entry_with_path)
        return ret
    
    
    def get_dir_content_old(path, include_folders=True, recursive=True, prepend_folder_name=True):
        path_len = len(path) + len(os.path.sep)
        return [item if prepend_folder_name else item[path_len:] for item in _get_dir_content_old(path, include_folders, recursive)]
    
    
    def main():
        root_dir = "root_dir"
        ret0 = get_dir_content(root_dir, include_folders=True, recursive=True, prepend_folder_name=True)
        lret0 = list(ret0)
        print(ret0, len(lret0), pformat(lret0))
        ret1 = get_dir_content_old(root_dir, include_folders=False, recursive=True, prepend_folder_name=False)
        print(len(ret1), pformat(ret1))
    
    
    if __name__ == "__main__":
        main()
    

    Notas :

    • Hay dos implementaciones:
      • Uno que usa generadores (por supuesto que aquí parece inútil, ya que inmediatamente convierto el resultado en una lista)
      • El clásico (nombres de funciones que terminan en _old )
    • Se utiliza la recursividad (para entrar en subdirectorios)
    • Para cada implementación hay dos funciones:
      • Uno que comienza con un guión bajo ( _ ): "privado" (no debe llamarse directamente) - eso hace todo el trabajo
      • El público (envoltorio sobre el anterior): simplemente elimina la ruta inicial (si es necesario) de las entradas devueltas. Es una implementación fea, pero es la única idea con la que puedo llegar en este momento.
    • En términos de rendimiento, los generadores son generalmente un poco más rápidos (considerando los tiempos de creación y de iteración ), pero no los probé en funciones recursivas, y también estoy iterando dentro de la función sobre generadores internos, no sé cómo funciona el rendimiento amigable es eso
    • Juega con los argumentos para obtener diferentes resultados


    Salida :

    (py35x64_test) E:\Work\Dev\StackOverflow\q003207219>"e:\Work\Dev\VEnvs\py35x64_test\Scripts\python.exe" "code_os_listdir.py"
    <generator object get_dir_content at 0x000001BDDBB3DF10> 22 ['root_dir\\dir0',
     'root_dir\\dir0\\dir00',
     'root_dir\\dir0\\dir00\\dir000',
     'root_dir\\dir0\\dir00\\dir000\\file0000',
     'root_dir\\dir0\\dir00\\file000',
     'root_dir\\dir0\\dir01',
     'root_dir\\dir0\\dir01\\file010',
     'root_dir\\dir0\\dir01\\file011',
     'root_dir\\dir0\\dir02',
     'root_dir\\dir0\\dir02\\dir020',
     'root_dir\\dir0\\dir02\\dir020\\dir0200',
     'root_dir\\dir1',
     'root_dir\\dir1\\file10',
     'root_dir\\dir1\\file11',
     'root_dir\\dir1\\file12',
     'root_dir\\dir2',
     'root_dir\\dir2\\dir20',
     'root_dir\\dir2\\dir20\\file200',
     'root_dir\\dir2\\file20',
     'root_dir\\dir3',
     'root_dir\\file0',
     'root_dir\\file1']
    11 ['dir0\\dir00\\dir000\\file0000',
     'dir0\\dir00\\file000',
     'dir0\\dir01\\file010',
     'dir0\\dir01\\file011',
     'dir1\\file10',
     'dir1\\file11',
     'dir1\\file12',
     'dir2\\dir20\\file200',
     'dir2\\file20',
     'file0',
     'file1']
    


  1. [Python 3]: os. scandir ( ruta = '.' ) ( Python 3.5 +, backport: [PyPI]: scandir )

    Return an iterator of os.DirEntry objects corresponding to the entries in the directory given by path. The entries are yielded in arbitrary order, and the special entries '.' and '..' are not included.

    Using scandir() instead of listdir() can significantly increase the performance of code that also needs file type or file attribute information, because os.DirEntry objects expose this information if the operating system provides it when scanning a directory. All os.DirEntry methods may perform a system call, but is_dir() and is_file() usually only require a system call for symbolic links; os.DirEntry.stat() always requires a system call on Unix but only requires one for symbolic links on Windows.


    >>> import os
    >>> root_dir = os.path.join(".", "root_dir")  # Explicitly prepending current directory
    >>> root_dir
    '.\\root_dir'
    >>>
    >>> scandir_iterator = os.scandir(root_dir)
    >>> scandir_iterator
    <nt.ScandirIterator object at 0x00000268CF4BC140>
    >>> [item.path for item in scandir_iterator]
    ['.\\root_dir\\dir0', '.\\root_dir\\dir1', '.\\root_dir\\dir2', '.\\root_dir\\dir3', '.\\root_dir\\file0', '.\\root_dir\\file1']
    >>>
    >>> [item.path for item in scandir_iterator]  # Will yield an empty list as it was consumed by previous iteration (automatically performed by the list comprehension)
    []
    >>>
    >>> scandir_iterator = os.scandir(root_dir)  # Reinitialize the generator
    >>> for item in scandir_iterator :
    ...     if os.path.isfile(item.path):
    ...             print(item.name)
    ...
    file0
    file1
    

    Notas :

    • Es similar a os.listdir
    • Pero también es más flexible (y ofrece más funcionalidad), más Python ic (y en algunos casos, más rápido)


  1. [Python 3]: os. caminar ( top, topdown = True, onerror = None, followlinks = False )

    Generate the file names in a directory tree by walking the tree either top-down or bottom-up. For each directory in the tree rooted at directory top (including top itself), it yields a 3-tuple (dirpath, dirnames, filenames).


    >>> import os
    >>> root_dir = os.path.join(os.getcwd(), "root_dir")  # Specify the full path
    >>> root_dir
    'E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir'
    >>>
    >>> walk_generator = os.walk(root_dir)
    >>> root_dir_entry = next(walk_generator)  # First entry corresponds to the root dir (passed as an argument)
    >>> root_dir_entry
    ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir', ['dir0', 'dir1', 'dir2', 'dir3'], ['file0', 'file1'])
    >>>
    >>> root_dir_entry[1] + root_dir_entry[2]  # Display dirs and files (direct descendants) in a single list
    ['dir0', 'dir1', 'dir2', 'dir3', 'file0', 'file1']
    >>>
    >>> [os.path.join(root_dir_entry[0], item) for item in root_dir_entry[1] + root_dir_entry[2]]  # Display all the entries in the previous list by their full path
    ['E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir0', 'E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir1', 'E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir2', 'E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir3', 'E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\file0', 'E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\file1']
    >>>
    >>> for entry in walk_generator:  # Display the rest of the elements (corresponding to every subdir)
    ...     print(entry)
    ...
    ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir0', ['dir00', 'dir01', 'dir02'], [])
    ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir0\\dir00', ['dir000'], ['file000'])
    ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir0\\dir00\\dir000', [], ['file0000'])
    ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir0\\dir01', [], ['file010', 'file011'])
    ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir0\\dir02', ['dir020'], [])
    ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir0\\dir02\\dir020', ['dir0200'], [])
    ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir0\\dir02\\dir020\\dir0200', [], [])
    ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir1', [], ['file10', 'file11', 'file12'])
    ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir2', ['dir20'], ['file20'])
    ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir2\\dir20', [], ['file200'])
    ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir3', [], [])
    

    Notas :

    • Debajo de las escenas, usa os.scandir( os.listdiren versiones anteriores)
    • Hace el trabajo pesado recurriendo a subcarpetas.


  1. [Python 3]: glob. glob ( nombre de ruta, *, recursivo = falso ) ( [Python 3]: glob. iglob ( nombre de ruta, *, recursivo = falso ) )

    Return a possibly-empty list of path names that match pathname, which must be a string containing a path specification. pathname can be either absolute (like /usr/src/Python-1.5/Makefile) or relative (like ../../Tools/*/*.gif), and can contain shell-style wildcards. Broken symlinks are included in the results (as in the shell).
    ...
    Changed in version 3.5: Support for recursive globs using “**”.


    >>> import glob, os
    >>> wildcard_pattern = "*"
    >>> root_dir = os.path.join("root_dir", wildcard_pattern)  # Match every file/dir name
    >>> root_dir
    'root_dir\\*'
    >>>
    >>> glob_list = glob.glob(root_dir)
    >>> glob_list
    ['root_dir\\dir0', 'root_dir\\dir1', 'root_dir\\dir2', 'root_dir\\dir3', 'root_dir\\file0', 'root_dir\\file1']
    >>>
    >>> [item.replace("root_dir" + os.path.sep, "") for item in glob_list]  # Strip the dir name and the path separator from begining
    ['dir0', 'dir1', 'dir2', 'dir3', 'file0', 'file1']
    >>>
    >>> for entry in glob.iglob(root_dir + "*", recursive=True):
    ...     print(entry)
    ...
    root_dir\
    root_dir\dir0
    root_dir\dir0\dir00
    root_dir\dir0\dir00\dir000
    root_dir\dir0\dir00\dir000\file0000
    root_dir\dir0\dir00\file000
    root_dir\dir0\dir01
    root_dir\dir0\dir01\file010
    root_dir\dir0\dir01\file011
    root_dir\dir0\dir02
    root_dir\dir0\dir02\dir020
    root_dir\dir0\dir02\dir020\dir0200
    root_dir\dir1
    root_dir\dir1\file10
    root_dir\dir1\file11
    root_dir\dir1\file12
    root_dir\dir2
    root_dir\dir2\dir20
    root_dir\dir2\dir20\file200
    root_dir\dir2\file20
    root_dir\dir3
    root_dir\file0
    root_dir\file1
    

    Notas :

    • Usos os.listdir
    • Para árboles grandes (especialmente si el recursivo está activado ), se prefiere iglob
    • Permite el filtrado avanzado basado en el nombre (debido al comodín)


  1. [Python 3]: clase pathlib. Ruta ( * segmentos de ruta ) ( Python 3.4 +, backport: [PyPI]: pathlib2 )

    >>> import pathlib
    >>> root_dir = "root_dir"
    >>> root_dir_instance = pathlib.Path(root_dir)
    >>> root_dir_instance
    WindowsPath('root_dir')
    >>> root_dir_instance.name
    'root_dir'
    >>> root_dir_instance.is_dir()
    True
    >>>
    >>> [item.name for item in root_dir_instance.glob("*")]  # Wildcard searching for all direct descendants
    ['dir0', 'dir1', 'dir2', 'dir3', 'file0', 'file1']
    >>>
    >>> [os.path.join(item.parent.name, item.name) for item in root_dir_instance.glob("*") if not item.is_dir()]  # Display paths (including parent) for files only
    ['root_dir\\file0', 'root_dir\\file1']
    

    Notas :

    • Esta es una forma de lograr nuestro objetivo.
    • Es el estilo OOP de manejar caminos
    • Ofrece muchas funcionalidades


  1. [Python 2]: dircache.listdir (ruta) ( solo Python 2 )


    def listdir(path):
        """List directory contents, using cache."""
        try:
            cached_mtime, list = cache[path]
            del cache[path]
        except KeyError:
            cached_mtime, list = -1, []
        mtime = os.stat(path).st_mtime
        if mtime != cached_mtime:
            list = os.listdir(path)
            list.sort()
        cache[path] = mtime, list
        return list
    


  1. [man7]: OPENDIR (3) / [man7]: READDIR (3) / [man7]: CLOSEDIR (3) a través de [Python 3]: ctypes - Una biblioteca de funciones foráneas para Python ( específico de POSIX )

    ctypes is a foreign function library for Python. It provides C compatible data types, and allows calling functions in DLLs or shared libraries. It can be used to wrap these libraries in pure Python.

    code_ctypes.py :

    #!/usr/bin/env python3
    
    import sys
    from ctypes import Structure, \
        c_ulonglong, c_longlong, c_ushort, c_ubyte, c_char, c_int, \
        CDLL, POINTER, \
        create_string_buffer, get_errno, set_errno, cast
    
    
    DT_DIR = 4
    DT_REG = 8
    
    char256 = c_char * 256
    
    
    class LinuxDirent64(Structure):
        _fields_ = [
            ("d_ino", c_ulonglong),
            ("d_off", c_longlong),
            ("d_reclen", c_ushort),
            ("d_type", c_ubyte),
            ("d_name", char256),
        ]
    
    LinuxDirent64Ptr = POINTER(LinuxDirent64)
    
    libc_dll = this_process = CDLL(None, use_errno=True)
    # ALWAYS set argtypes and restype for functions, otherwise it's UB!!!
    opendir = libc_dll.opendir
    readdir = libc_dll.readdir
    closedir = libc_dll.closedir
    
    
    def get_dir_content(path):
        ret = [path, list(), list()]
        dir_stream = opendir(create_string_buffer(path.encode()))
        if (dir_stream == 0):
            print("opendir returned NULL (errno: {:d})".format(get_errno()))
            return ret
        set_errno(0)
        dirent_addr = readdir(dir_stream)
        while dirent_addr:
            dirent_ptr = cast(dirent_addr, LinuxDirent64Ptr)
            dirent = dirent_ptr.contents
            name = dirent.d_name.decode()
            if dirent.d_type & DT_DIR:
                if name not in (".", ".."):
                    ret[1].append(name)
            elif dirent.d_type & DT_REG:
                ret[2].append(name)
            dirent_addr = readdir(dir_stream)
        if get_errno():
            print("readdir returned NULL (errno: {:d})".format(get_errno()))
        closedir(dir_stream)
        return ret
    
    
    def main():
        print("{:s} on {:s}\n".format(sys.version, sys.platform))
        root_dir = "root_dir"
        entries = get_dir_content(root_dir)
        print(entries)
    
    
    if __name__ == "__main__":
        main()
    

    Notas :

    • Carga las tres funciones de libc (cargadas en el proceso actual) y las llama (para más detalles verifique [SO]: ¿Cómo verifico si un archivo existe sin excepciones? (Respuesta de @ CristiFati) - últimas notas del ítem # 4. ). Eso colocaría este enfoque muy cerca del borde de Python / C
    • LinuxDirent64 es la representación ctypes de struct dirent64 de [man7]: dirent.h (0P) (también lo son las constantes DT_ ) de mi máquina: Ubtu 16 x64 ( 4.10.0-40-generic y libc6-dev: amd64 ). En otros sabores / versiones, la definición de la estructura puede diferir y, de ser así, el alias de ctypes debe actualizarse; de ​​lo contrario, se producirá un comportamiento indefinido.
    • Devuelve datos en os.walkformato de. No me molesté en hacerlo recursivo, pero a partir del código existente, sería una tarea bastante trivial.
    • Todo es factible en Win también, los datos (bibliotecas, funciones, estructuras, constantes, ...) difieren


    Salida :

    [[email protected]:~/Work/Dev/StackOverflow/q003207219]> ./code_ctypes.py
    3.5.2 (default, Nov 12 2018, 13:43:14)
    [GCC 5.4.0 20160609] on linux
    
    ['root_dir', ['dir2', 'dir1', 'dir3', 'dir0'], ['file1', 'file0']]
    


  1. [ActiveState.Docs]: win32file.FindFilesW ( específico de Win )

    Retrieves a list of matching filenames, using the Windows Unicode API. An interface to the API FindFirstFileW/FindNextFileW/Find close functions.


    >>> import os, win32file, win32con
    >>> root_dir = "root_dir"
    >>> wildcard = "*"
    >>> root_dir_wildcard = os.path.join(root_dir, wildcard)
    >>> entry_list = win32file.FindFilesW(root_dir_wildcard)
    >>> len(entry_list)  # Don't display the whole content as it's too long
    8
    >>> [entry[-2] for entry in entry_list]  # Only display the entry names
    ['.', '..', 'dir0', 'dir1', 'dir2', 'dir3', 'file0', 'file1']
    >>>
    >>> [entry[-2] for entry in entry_list if entry[0] & win32con.FILE_ATTRIBUTE_DIRECTORY and entry[-2] not in (".", "..")]  # Filter entries and only display dir names (except self and parent)
    ['dir0', 'dir1', 'dir2', 'dir3']
    >>>
    >>> [os.path.join(root_dir, entry[-2]) for entry in entry_list if entry[0] & (win32con.FILE_ATTRIBUTE_NORMAL | win32con.FILE_ATTRIBUTE_ARCHIVE)]  # Only display file "full" names
    ['root_dir\\file0', 'root_dir\\file1']
    

    Notas :


  1. Instale algún (otro) paquete de terceros que haga el truco
    • Lo más probable es que dependa de uno (o más) de los anteriores (tal vez con ligeras personalizaciones)


Notas :

  • El código está destinado a ser portátil (excepto los lugares que se dirigen a un área específica, que están marcados) o cruzan:

    • plataforma ( Nix , Win ,)
    • Versión de Python (2, 3,)
  • Se utilizaron varios estilos de ruta (absolutos, parientes) en las variantes anteriores, para ilustrar el hecho de que las "herramientas" utilizadas son flexibles en esta dirección.

  • os.listdiry os.scandiruse opendir / readdir / closedir ( [MS.Docs]: función FindFirstFileW / [MS.Docs]: función FindNextFileW / [MS.Docs]: función FindClose ) (a través de [GitHub]: python / cpython - (maestro) cpython / Módulos / posixmodule.c )

  • win32file.FindFilesWtambién usa esas funciones ( específicas de Win ) (a través de [GitHub]: mhammond / pywin32 - (maestro) pywin32 / win32 / src / win32file.i )

  • _get_dir_content (desde el punto # 1. ) se puede implementar usando cualquiera de estos enfoques (algunos requerirán más trabajo y otros menos)

    • Algunos filtrado avanzado (en lugar de sólo archivo vs. dir) podría hacerse: por ejemplo, el include_folders argumento podría ser reemplazado por otro (por ejemplo filter_func ), que sería una función que toma un camino como un argumento: filter_func=lambda x: True(esto no retirar de él cualquier cosa) y dentro de _get_dir_content algo como: if not filter_func(entry_with_path): continue(si la función falla para una entrada, se omitirá), pero cuanto más complejo se vuelve el código, más tiempo tardará en ejecutarse
  • Nota bene! Dado que se usa la recursividad, debo mencionar que hice algunas pruebas en mi computadora portátil ( Win 10 x64 ), totalmente ajenas a este problema, y ​​cuando el nivel de recursividad alcanzaba valores en algún lugar del rango ( 990 .. 1000) ( límite de recursividad - 1000 (predeterminado)), obtuve StackOverflow :). Si el árbol de directorios excede ese límite (no soy un experto en FS , así que no sé si eso es posible), eso podría ser un problema.
    También debo mencionar que no intenté aumentar el límite de recursividad porque no tengo experiencia en el área (cuánto puedo aumentar antes de tener que aumentar también la pila en OSlevel), pero en teoría siempre existirá la posibilidad de falla, si la profundidad del directorio es mayor que el límite de recursividad más alto posible (en esa máquina)

  • Los ejemplos de código son solo para fines demostrativos. Eso significa que no tomé en cuenta el manejo de errores (no creo que haya ningún intento / excepto / else / bloque finalmente ), por lo que el código no es robusto (la razón es: mantenerlo lo más simple y corto posible ). Para la producción , también se debe agregar el manejo de errores

Otros enfoques:

  1. Use Python solo como envoltorio

    • Todo se hace con otra tecnología
    • Esa tecnología se invoca desde Python
    • El sabor más famoso que conozco es lo que llamo el enfoque del administrador del sistema :

      • Use Python (o cualquier lenguaje de programación para el caso) para ejecutar comandos de shell (y analizar sus resultados)
      • Algunos consideran que esto es un buen truco
      • Lo considero más como una solución poco convincente ( gainarie ), ya que la acción per se se realiza desde el shell ( cmd en este caso) y, por lo tanto, no tiene nada que ver con Python .
      • El filtrado ( grep/ findstr) o el formateo de salida se pueden hacer en ambos lados, pero no voy a insistir en ello. Además, usé deliberadamente en os.systemlugar de subprocess.Popen.
      (py35x64_test) E:\Work\Dev\StackOverflow\q003207219>"e:\Work\Dev\VEnvs\py35x64_test\Scripts\python.exe" -c "import os;os.system(\"dir /b root_dir\")"
      dir0
      dir1
      dir2
      dir3
      file0
      file1
      

    En general, este enfoque debe evitarse, ya que si algún formato de salida de comando difiere ligeramente entre las versiones / sabores del sistema operativo , el código de análisis también debe adaptarse; sin mencionar las diferencias entre los lugares).

0
49

Me gustó mucho la respuesta de Adamk , sugiriendo que use glob(), desde el módulo del mismo nombre. Esto le permite hacer coincidir patrones con *s.

Pero como otras personas señalaron en los comentarios, glob()pueden tropezarse con direcciones de barra inconsistentes. Para ayudar con eso, le sugiero que use las funciones join()y expanduser()en el os.pathmódulo, y quizás también la getcwd()función en el osmódulo.

Como ejemplos:

from glob import glob

# Return everything under C:\Users\admin that contains a folder called wlp.
glob('C:\Users\admin\*\wlp')

Lo anterior es terrible: la ruta ha sido codificada y solo funcionará en Windows entre el nombre de la unidad y los \correos electrónicos codificados en la ruta.

from glob    import glob
from os.path import join

# Return everything under Users, admin, that contains a folder called wlp.
glob(join('Users', 'admin', '*', 'wlp'))

Lo anterior funciona mejor, pero se basa en el nombre de la carpeta Usersque a menudo se encuentra en Windows y no tan a menudo en otros sistemas operativos. También se basa en que el usuario tenga un nombre específico, admin.

from glob    import glob
from os.path import expanduser, join

# Return everything under the user directory that contains a folder called wlp.
glob(join(expanduser('~'), '*', 'wlp'))

Esto funciona perfectamente en todas las plataformas.

Otro gran ejemplo que funciona perfectamente en todas las plataformas y hace algo un poco diferente:

from glob    import glob
from os      import getcwd
from os.path import join

# Return everything under the current directory that contains a folder called wlp.
glob(join(getcwd(), '*', 'wlp'))

Espero que estos ejemplos te ayuden a ver el poder de algunas de las funciones que puedes encontrar en los módulos estándar de la biblioteca de Python.

1
38
def list_files(path):
    # returns a list of names (with extension, without full path) of all files 
    # in folder path
    files = []
    for name in os.listdir(path):
        if os.path.isfile(os.path.join(path, name)):
            files.append(name)
    return files 
0
24

Si está buscando una implementación de Python de find , esta es una receta que uso con bastante frecuencia:

from findtools.find_files import (find_files, Match)

# Recursively find all *.sh files in **/usr/bin**
sh_files_pattern = Match(filetype='f', name='*.sh')
found_files = find_files(path='/usr/bin', match=sh_files_pattern)

for found_file in found_files:
    print found_file

Así que hice un paquete PyPI y también hay un repositorio de GitHub . Espero que alguien lo encuentre potencialmente útil para este código.

0
15

Para obtener mejores resultados, puede usar el listdir()método del osmódulo junto con un generador (un generador es un iterador poderoso que mantiene su estado, ¿recuerdas?). El siguiente código funciona bien con ambas versiones: Python 2 y Python 3.

Aquí tienes un código:

import os

def files(path):  
    for file in os.listdir(path):
        if os.path.isfile(os.path.join(path, file)):
            yield file

for file in files("."):  
    print (file)

El listdir()método devuelve la lista de entradas para el directorio dado. El método os.path.isfile()devuelve Truesi la entrada dada es un archivo. Y el yieldoperador sale de la función pero mantiene su estado actual, y devuelve solo el nombre de la entrada detectada como un archivo. Todo lo anterior nos permite recorrer la función del generador.

11

Devuelve una lista de rutas de archivo absolutas, no recurre a subdirectorios

L = [os.path.join(os.getcwd(),f) for f in os.listdir('.') if os.path.isfile(os.path.join(os.getcwd(),f))]
2
  • 2
    Nota: os.path.abspath(f)sería un sustituto algo más económico de os.path.join(os.getcwd(),f). ShadowRanger 6 de mayo de 2017 a las 0:14
  • 1
    Sería aún más eficiente si comenzara con cwd = os.path.abspath('.'), luego lo usara en cwdlugar de '.'y en os.getcwd()todo momento para evitar un montón de llamadas al sistema redundantes. Martijn Pieters 5/12/18 a las 10:46
11

Un maestro sabio me dijo una vez que:

When there are several established ways to do something, none of them is good for all cases.

Por lo tanto, agregaré una solución para un subconjunto del problema: muy a menudo, solo queremos verificar si un archivo coincide con una cadena inicial y una cadena final, sin entrar en subdirectorios. Por lo tanto, nos gustaría una función que devuelva una lista de nombres de archivos, como:

filenames = dir_filter('foo/baz', radical='radical', extension='.txt')

Si desea declarar primero dos funciones, puede hacerlo:

def file_filter(filename, radical='', extension=''):
    "Check if a filename matches a radical and extension"
    if not filename:
        return False
    filename = filename.strip()
    return(filename.startswith(radical) and filename.endswith(extension))

def dir_filter(dirname='', radical='', extension=''):
    "Filter filenames in directory according to radical and extension"
    if not dirname:
        dirname = '.'
    return [filename for filename in os.listdir(dirname)
                if file_filter(filename, radical, extension)]

Esta solución podría generalizarse fácilmente con expresiones regulares (y es posible que desee agregar un patternargumento, si no desea que sus patrones se adhieran siempre al principio o al final del nombre del archivo).

0
10
import os
import os.path


def get_files(target_dir):
    item_list = os.listdir(target_dir)

    file_list = list()
    for item in item_list:
        item_dir = os.path.join(target_dir,item)
        if os.path.isdir(item_dir):
            file_list += get_files(item_dir)
        else:
            file_list.append(item_dir)
    return file_list

Aquí utilizo una estructura recursiva.

1
  • Lo mismo se puede lograr solo en una línea con pathlib:filter(Path.is_file, Path().rglob('*'))Georgy 17 de mayo de 2019 a las 9:37
6

Usando generadores

import os
def get_files(search_path):
     for (dirpath, _, filenames) in os.walk(search_path):
         for filename in filenames:
             yield os.path.join(dirpath, filename)
list_files = get_files('.')
for filename in list_files:
    print(filename)
5

Otra variante muy legible para Python 3.4+ es usar pathlib.Path.glob:

from pathlib import Path
folder = '/foo'
[f for f in Path(folder).glob('*') if f.is_file()]

Es simple hacer más específico, por ejemplo, busque solo archivos fuente de Python que no sean enlaces simbólicos, también en todos los subdirectorios:

[f for f in Path(folder).glob('**/*.py') if not f.is_symlink()]
4

Para Python 2:

pip install rglob

Entonces hazlo

import rglob
file_list = rglob.rglob("/home/base/dir/", "*")
print file_list
1
  • 2
    Cuando se pueda evitar una depuración externa, hágalo. ¿Cuál es el valor añadido de utilizar una dependencia externa cuando todo lo que necesita ya está en el idioma? Eric 30 de marzo a las 13:45
3

Aquí está mi función de propósito general para esto. Devuelve una lista de rutas de archivo en lugar de nombres de archivo, ya que me pareció más útil. Tiene algunos argumentos opcionales que lo hacen versátil. Por ejemplo, a menudo lo uso con argumentos como pattern='*.txt'o subfolders=True.

import os
import fnmatch

def list_paths(folder='.', pattern='*', case_sensitive=False, subfolders=False):
    """Return a list of the file paths matching the pattern in the specified 
    folder, optionally including files inside subfolders.
    """
    match = fnmatch.fnmatchcase if case_sensitive else fnmatch.fnmatch
    walked = os.walk(folder) if subfolders else [next(os.walk(folder))]
    return [os.path.join(root, f)
            for root, dirnames, filenames in walked
            for f in filenames if match(f, pattern)]
2

Proporcionaré un ejemplo de una línea donde se pueden proporcionar la ruta de origen y el tipo de archivo como entrada. El código devuelve una lista de nombres de archivo con la extensión csv. Utilice . en caso de que sea necesario devolver todos los archivos. Esto también escanea recursivamente los subdirectorios.

[y for x in os.walk(sourcePath) for y in glob(os.path.join(x[0], '*.csv'))]

Modifique las extensiones de archivo y la ruta de origen según sea necesario.

1
  • 1
    Si va a usar glob, simplemente use glob('**/*.csv', recursive=True). No es necesario combinar esto con os.walk()recurse ( recursivey **son compatibles desde Python 3.5). Martijn Pieters 5/12/18 a las 11:09
2

dircache está "En desuso desde la versión 2.6: el módulo dircache se ha eliminado en Python 3.0".

import dircache
list = dircache.listdir(pathname)
i = 0
check = len(list[0])
temp = []
count = len(list)
while count != 0:
  if len(list[i]) != check:
     temp.append(list[i-1])
     check = len(list[i])
  else:
    i = i + 1
    count = count - 1

print temp
0