Lectura de carpeta recursiva de Python

Tengo un fondo de C ++ / Obj-C y acabo de descubrir Python (lo he estado escribiendo durante aproximadamente una hora). Estoy escribiendo un script para leer recursivamente el contenido de los archivos de texto en una estructura de carpetas.

El problema que tengo es que el código que he escrito solo funcionará para una carpeta de profundidad. Puedo ver por qué en el código (ver #hardcoded path ), simplemente no sé cómo puedo seguir adelante con Python ya que mi experiencia con él es solo nueva.

Código Python:

 import os import sys rootdir = sys.argv[1] for root, subFolders, files in os.walk(rootdir): for folder in subFolders: outfileName = rootdir + "/" + folder + "/py-outfile.txt" # hardcoded path folderOut = open( outfileName, 'w' ) print "outfileName is " + outfileName for file in files: filePath = rootdir + '/' + file f = open( filePath, 'r' ) toWrite = f.read() print "Writing '" + toWrite + "' to" + filePath folderOut.write( toWrite ) f.close() folderOut.close() 

Asegúrese de comprender los tres valores de retorno de os.walk :

 for root, subdirs, files in os.walk(rootdir): 

tiene el siguiente significado:

  • root : ruta actual que se “recorrió”
  • subdirs : Archivos en la root del directorio de tipo
  • files : archivos en la root (no en subdirs ) de tipo distinto al directorio

¡Y por favor use os.path.join lugar de concatenar con una barra! Su problema es filePath = rootdir + '/' + file : debe concatenar la carpeta “caminada” actualmente en lugar de la carpeta superior. De modo que debe ser filePath = os.path.join(root, file) . Por cierto, el “archivo” es un componente, por lo que normalmente no lo usa como nombre de variable.

Otro problema son tus bucles, que deberían ser así, por ejemplo:

 import os import sys walk_dir = sys.argv[1] print('walk_dir = ' + walk_dir) # If your current working directory may change during script execution, it's recommended to # immediately convert program arguments to an absolute path. Then the variable root below will # be an absolute path as well. Example: # walk_dir = os.path.abspath(walk_dir) print('walk_dir (absolute) = ' + os.path.abspath(walk_dir)) for root, subdirs, files in os.walk(walk_dir): print('--\nroot = ' + root) list_file_path = os.path.join(root, 'my-directory-list.txt') print('list_file_path = ' + list_file_path) with open(list_file_path, 'wb') as list_file: for subdir in subdirs: print('\t- subdirectory ' + subdir) for filename in files: file_path = os.path.join(root, filename) print('\t- file %s (full path: %s)' % (filename, file_path)) with open(file_path, 'rb') as f: f_content = f.read() list_file.write(('The file %s contains:\n' % filename).encode('utf-8')) list_file.write(f_content) list_file.write(b'\n') 

Si no lo sabía, la instrucción with para archivos es una abreviatura:

 with open('filename', 'rb') as f: dosomething() # is effectively the same as f = open('filename', 'rb') try: dosomething() finally: f.close() 

Si está utilizando Python 3.5 o superior, puede hacerlo en 1 línea.

 import glob for filename in glob.iglob(root_dir + '**/*.txt', recursive=True): print(filename) 

Como se menciona en la documentación.

Si recursivo es verdadero, el patrón ‘**’ coincidirá con cualquier archivo y cero o más directorios y subdirectorios.

Si quieres cada archivo, puedes usar

 import glob for filename in glob.iglob(root_dir + '**/*', recursive=True): print(filename) 

De acuerdo con Dave Webb, os.walk generará un elemento para cada directorio en el árbol. El hecho es que simplemente no tienes que preocuparte por las subFolders .

Código como este debería funcionar:

 import os import sys rootdir = sys.argv[1] for folder, subs, files in os.walk(rootdir): with open(os.path.join(folder, 'python-outfile.txt'), 'w') as dest: for filename in files: with open(os.path.join(folder, filename), 'r') as src: dest.write(src.read()) 

use os.path.join() para construir sus rutas – es más ordenado:

 import os import sys rootdir = sys.argv[1] for root, subFolders, files in os.walk(rootdir): for folder in subFolders: outfileName = os.path.join(root,folder,"py-outfile.txt") folderOut = open( outfileName, 'w' ) print "outfileName is " + outfileName for file in files: filePath = os.path.join(root,file) toWrite = open( filePath).read() print "Writing '" + toWrite + "' to" + filePath folderOut.write( toWrite ) folderOut.close() 
 import glob import os root_dir =  for filename in glob.iglob(root_dir + '**/**', recursive=True): if os.path.isfile(filename): with open(filename,'r') as file: print(file.read()) 

**/** se utiliza para obtener todos los archivos de forma recursiva, incluido el directory .

if os.path.isfile(filename) se usa if os.path.isfile(filename) para verificar si la variable de filename file es file o directory , si es archivo, entonces podemos leer ese archivo. Aquí estoy imprimiendo archivo.

Prueba esto:

 import os import sys for root, subdirs, files in os.walk(path): for file in os.listdir(root): filePath = os.path.join(root, file) if os.path.isdir(filePath): pass else: f = open (filePath, 'r') # Do Stuff 

Si desea una lista plana de todas las rutas bajo un directorio dado (como find . en el shell):

  files = [ os.path.join(parent, name) for (parent, subdirs, files) in os.walk(YOUR_DIRECTORY) for name in files + subdirs ] 

Para incluir solo las rutas completas a los archivos bajo el directorio base, + subdirs .

os.walk realiza la caminata recursiva por defecto. Para cada dir, a partir de la raíz, se obtiene una tupla de 3 (dirpath, dirnames, filenames)

 from os import walk from os.path import splitext, join def select_files(root, files): """ simple logic here to filter out interesting files .py files in this example """ selected_files = [] for file in files: #do concatenation here to get full path full_path = join(root, file) ext = splitext(file)[1] if ext == ".py": selected_files.append(full_path) return selected_files def build_recursive_dir_tree(path): """ path - where to begin folder scan """ selected_files = [] for root, dirs, files in walk(path): selected_files += select_files(root, files) return selected_files 

Creo que el problema es que no estás procesando la salida de os.walk correctamente.

En primer lugar, el cambio:

 filePath = rootdir + '/' + file 

a:

 filePath = root + '/' + file 

rootdir es su directorio de inicio fijo; root es un directorio devuelto por os.walk .

En segundo lugar, no es necesario sangrar el bucle de procesamiento de archivos, ya que no tiene sentido ejecutar esto para cada subdirectorio. Obtendrá root set en cada subdirectorio. No es necesario procesar los subdirectorios a mano, a menos que desee hacer algo con los propios directorios.