Iterando a través de directorios con Python


158

Necesito recorrer los subdirectorios de un directorio determinado y buscar archivos. Si obtengo un archivo, tengo que abrirlo, cambiar el contenido y reemplazarlo con mis propias líneas.

Intenté esto:

import os

rootdir ='C:/Users/sid/Desktop/test'

for subdir, dirs, files in os.walk(rootdir):
    for file in files:
        f=open(file,'r')
        lines=f.readlines()
        f.close()
        f=open(file,'w')
        for line in lines:
            newline = "No you are not"
            f.write(newline)
        f.close()

pero recibo un error ¿Qué estoy haciendo mal?


13
"Un error": ¿algún error en particular?
— Daniel Roseman

1
Por favor, ¿podría explicar un poco sobre lo que espera hacer con los archivos / directorios una vez que los revise y trabaje según lo previsto? También proporcione detalles de error.
— ChrisProsser

1
El mensaje de error que estoy recibiendo es que no se encuentra el archivo cool.txt. En mi carpeta de prueba tengo otra carpeta llamada src y en la carpeta src tengo otra carpeta llamada main, en esta carpeta tengo cool.txt
— Wolf

44
¿puedes escribir el error en la pregunta? es más que molesto e innecesario tener que leer los comentarios para encontrarlo.
— Charlie Parker

1
más de un año después, ¿no puedo creer que haya vuelto a solicitar que se publique el error? @Wolf
— Charlie Parker

Respuestas:


301

El recorrido real a través de los directorios funciona tal como lo ha codificado. Si reemplaza el contenido del bucle interno con una printdeclaración simple , puede ver que se encuentra cada archivo:

import os
rootdir = 'C:/Users/sid/Desktop/test'

for subdir, dirs, files in os.walk(rootdir):
    for file in files:
        print os.path.join(subdir, file)

Si aún recibe errores al ejecutar lo anterior, proporcione el mensaje de error.


Actualizado para Python3

import os
rootdir = 'C:/Users/sid/Desktop/test'

for subdir, dirs, files in os.walk(rootdir):
    for file in files:
        print(os.path.join(subdir, file))

1
C: / Users / sid / Desktop / test \ src \ app / cool.txt C: / Users / sid / Desktop / test \ src \ app / woohoo.txt Ya en la declaración abierta de mi código, creo que tengo que dar la ruta absoluta al archivo. import os rootdir = 'C: / Users / spemmara / Desktop / test / src / app /' para subdir, directorios, archivos en os.walk (rootdir): para archivo en archivos: f = abierto (subdir + '/' + archivo , 'r') líneas = f.readlines () f.close () f = abierto (subdir + '/' + archivo, 'w') para línea en líneas: newline = "hey i know" f.write (newline) f.close () Gracias hombre. Está resuelto
— Wolf

3
¡Hola! Tenga en cuenta que la "impresión" en python 3 requiere paréntesis, de lo contrario, devuelve un error de sintaxis. ¡Espero que esto ayude!
— Tommaso Di Noto

14

Otra forma de devolver todos los archivos en subdirectorios es usar el pathlibmódulo , introducido en Python 3.4, que proporciona un enfoque orientado a objetos para manejar las rutas del sistema de archivos (Pathlib también está disponible en Python 2.7 a través del módulo pathlib2 en PyPi ):

from pathlib import Path

rootdir = Path('C:/Users/sid/Desktop/test')
# Return a list of regular files only, not directories
file_list = [f for f in rootdir.glob('**/*') if f.is_file()]

# For absolute paths instead of relative the current dir
file_list = [f for f in rootdir.resolve().glob('**/*') if f.is_file()]

Desde Python 3.5, el globmódulo también admite la búsqueda recursiva de archivos:

import os
from glob import iglob

rootdir_glob = 'C:/Users/sid/Desktop/test/**/*' # Note the added asterisks
# This will return absolute paths
file_list = [f for f in iglob('**/*', recursive=True) if os.path.isfile(f)]

El file_listde cualquiera de los enfoques anteriores se puede repetir sin la necesidad de un bucle anidado:

for f in file_list:
    print(f) # Replace with desired operations

1
¿Qué es preferible aquí para Python 3.6?
— PhoenixDev

@ PhoenixDev No he oído hablar de un enfoque recomendado sobre el otro en general. Prefiero usarme a pathlibmí mismo, principalmente porque me gusta la sintaxis de métodos orientados a objetos. Existen otras diferencias, como la biblioteca de rutas que devuelve clases de ruta específicas en lugar de cadenas, y las funciones disponibles difieren entre las bibliotecas (por ejemplo, os.path.expanduser('~')vs Path.home()). Examine la documentación y vea qué enfoque prefiere.
— joelostblom

En lugar de agregar **el patrón global, puede usar rglob.
— Georgy

12

A partir de 2020 , glob.iglob(path/**, recursive=True)parece la solución más pitónica , es decir:

import glob, os

for filename in glob.iglob('/pardadox-music/**', recursive=True):
    if os.path.isfile(filename): # filter dirs
        print(filename)

Salida:

/pardadox-music/modules/her1.mod
/pardadox-music/modules/her2.mod
...

Notas:
1 - glob.iglob

glob.iglob(pathname, recursive=False)

Devuelve un iterador que produce los mismos valores que glob()sin almacenarlos todos simultáneamente.

2 - Si es recursivo True, el patrón '**'coincidirá con cualquier archivo y cero o más directoriesy subdirectories.

3 - Si el directorio contiene archivos que comienzan con  .ellos, no coincidirán de manera predeterminada. Por ejemplo, considere un directorio que contiene  card.gif y .card.gif:

>>> import glob
>>> glob.glob('*.gif') ['card.gif'] 
>>> glob.glob('.c*')['.card.gif']

4 - También puede usar rglob(pattern), que es lo mismo que llamar  glob() con **/agregado en frente del patrón relativo dado.


1
Esta solución pitónica no enumera los archivos ocultos (también conocidos como archivos de puntos) mientras que el aceptado sí lo hace.
— ashrasmun

@ashrasmun Lo que mencionas está bien explicado en docs.python.org/3/library/glob.html
— CONvid19
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.