2009-04-28 26 views
89

Estoy intentando escribir un script de Python simple que copiará un index.tpl a index.html en todos los subdirectorios (con algunas excepciones).Cómo obtener todos los subdirectorios inmediatos en Python

Me estoy atascado tratando de obtener la lista de subdirectorios.

+8

Es posible que la respuesta aceptada a esta pregunta SO anterior resuelve el problema: http://stackoverflow.com/questions/120656/directory-listing-in-python –

Respuesta

154
import os 
def get_immediate_subdirectories(a_dir): 
    return [name for name in os.listdir(a_dir) 
      if os.path.isdir(os.path.join(a_dir, name))] 
8

os.walk es su amigo en esta situación.

Directamente de la documentación:

paseo() genera los nombres de los archivos en un árbol de directorios, por recorrer el árbol, ya sea de arriba hacia abajo o de abajo hacia arriba. Para cada directorio en el árbol enraizado en la parte superior del directorio (incluida la parte superior misma), se obtiene una tupla de 3 (dirpath, dirnames, filenames).

+1

Sólo ten en cuenta que si solo deseas los subdirectorios de primer nivel salen de la iteración os.walk después del primer conjunto de valores devueltos. – yoyo

6

Usando el modulo FilePath de Twisted:

from twisted.python.filepath import FilePath 

def subdirs(pathObj): 
    for subpath in pathObj.walk(): 
     if subpath.isdir(): 
      yield subpath 

if __name__ == '__main__': 
    for subdir in subdirs(FilePath(".")): 
     print "Subdirectory:", subdir 

Debido a que algunos comentaristas han preguntado cuáles son las ventajas de la utilización de las bibliotecas de Twisted para esto es, voy a ir un poco más allá de la pregunta original aquí.


Hay some improved documentation en una rama que explica las ventajas de FilePath; es posible que desee leer eso.

Más específicamente en este ejemplo: a diferencia de la versión de biblioteca estándar, esta función se puede implementar con sin importaciones. La función "subdivisiones" es totalmente genérica, ya que no opera más que en su argumento. Para copiar y mover los archivos usando la biblioteca estándar, necesita depender del "open" incorporado, "listdir", quizás "isdir" o "os.walk" o "shutil.copy". Tal vez "os.path.join" también. Sin mencionar el hecho de que necesita una cadena pasó un argumento para identificar el archivo real. Vamos a echar un vistazo a la aplicación plena el cual copia "index.tpl" de cada directorio a "index.html":

def copyTemplates(topdir): 
    for subdir in subdirs(topdir): 
     tpl = subdir.child("index.tpl") 
     if tpl.exists(): 
      tpl.copyTo(subdir.child("index.html")) 

La función "subdirectorios" arriba pueden trabajar en cualquier objeto -como FilePath. Lo que significa, entre otras cosas, objetos ZipPath. Desafortunadamente, ZipPath es de solo lectura en este momento, pero podría extenderse para admitir la escritura.

También puede pasar sus propios objetos para fines de prueba. Para probar las API de uso de os.path que se sugieren aquí, debe recurrir a nombres importados y dependencias implícitas y, en general, realizar magia negra para que sus pruebas funcionen. Con FilePath, haces algo como esto:

class MyFakePath: 
    def child(self, name): 
     "Return an appropriate child object" 

    def walk(self): 
     "Return an iterable of MyFakePath objects" 

    def exists(self): 
     "Return true or false, as appropriate to the test" 

    def isdir(self): 
     "Return true or false, as appropriate to the test" 
... 
subdirs(MyFakePath(...)) 
+0

Como tengo poca exposición a Twisted, siempre recibo información adicional y ejemplos; esta respuesta es agradable de ver para eso. Una vez dicho esto, dado que este enfoque parece requerir mucho más trabajo que el uso de los módulos incorporados de python, y una instalación Twisted, ¿hay alguna ventaja de usar esto que pueda agregar a la respuesta? –

+1

La respuesta de Glyph probablemente se inspiró en el hecho de que TwistedLore también usa archivos .tpl. – Constantin

+0

Bueno, claramente no espero la inquisición española :-) Supuse que "* .tpl" era una referencia genérica a alguna extensión abstracta que significa "plantilla", y no una plantilla Twisted específica (he visto .tpl usado en muchos idiomas después de todo). Bueno saber. –

1

Aquí hay una manera:

import os 
import shutil 

def copy_over(path, from_name, to_name): 
    for path, dirname, fnames in os.walk(path): 
    for fname in fnames: 
     if fname == from_name: 
     shutil.copy(os.path.join(path, from_name), os.path.join(path, to_name)) 


copy_over('.', 'index.tpl', 'index.html') 
+0

-1: no funcionará, ya que shutil.copy copiará en el directorio actual, por lo que terminará sobrescribiendo 'index.html' en el directorio actual una vez por cada 'index.tpl' que encuentre en el árbol de subdirectorios . – nosklo

+0

Se corrigió el código, ¡gracias! –

2

acabo escribió algo de código para mover máquinas virtuales de VMware en todo, y terminó usando os.path y shutil para llevar a cabo la copia de archivos entre subdirectorios.

def copy_client_files (file_src, file_dst): 
    for file in os.listdir(file_src): 
      print "Copying file: %s" % file 
      shutil.copy(os.path.join(file_src, file), os.path.join(file_dst, file)) 

No es terriblemente elegante, pero funciona.

13
import os, os.path 

Para llegar (ruta completa) subdirectorios inmediatos en un directorio:

def SubDirPath (d): 
    return filter(os.path.isdir, [os.path.join(d,f) for f in os.listdir(d)]) 

para obtener la última (más reciente) subdirectorio:

def LatestDirectory (d): 
    return max(SubDirPath(d), key=os.path.getmtime) 
46

¿Por qué nadie ha mencionado glob? glob le permite usar la expansión de nombre de ruta estilo Unix, y es mi función ir para casi todo lo que necesita para encontrar más de un nombre de ruta. Esto hace que sea muy fácil:

from glob import glob 
paths = glob('*/') 

Tenga en cuenta que glob devolverá el directorio con la barra final (como Unix serían), mientras que la mayoría de las soluciones basadas path se omita la barra final.

+2

Buena solución, simple y funciona. Para aquellos que no quieran esa barra diagonal final, puede usar este 'paths = [p.replace ('/', '') para p en glob ('* /')]'. –

+3

Podría ser más seguro simplemente cortar el último carácter con '[p [: - 1] para p en las rutas]', ya que ese método de reemplazo también reemplazará cualquier barra diagonal escapada en el nombre del archivo (no es común). – ari

+2

Incluso más seguro, use una tira ('/') para quitar las barras posteriores.De esta manera se garantiza que no se eliminen los caracteres que no sean barras diagonales –

9

Verificar "Getting a list of all subdirectories in the current directory".

Aquí hay una versión de Python 3:

import os 

dir_list = next(os.walk('.'))[1] 

print(dir_list) 
+0

Sería más borrar si 'file_list' se reemplazó con' dir_list', porque '[1]' devuelve la lista de directorios. – wisbucky

+0

@wisbucky punto justo, he actualizado mi respuesta. –

+1

** Extremadamente inteligente. ** Aunque la eficiencia no importa (_... lo hace totalmente), tengo curiosidad sobre si esto o la expresión del generador basado en glob '(s.rstrip ("/") para s en glob (parent_dir + "* /")) 'es más eficiente con el tiempo. Mi intuición intuitiva es que una '' base * basada en 'stat()' os.walk() 'solution * debe * ser profundamente más rápida que el globbing estilo shell. Lamentablemente, carezco de la voluntad de 'timeit' y realmente lo descubro. –

6

Este método muy bien lo hace todo de una sola vez.

from glob import glob 
subd = [s.rstrip("/") for s in glob(parent_dir+"*/")] 
Cuestiones relacionadas