web-dev-qa-db-fra.com

Dossier Python récursif lu

J'ai un arrière-plan C++/Obj-C et je viens de découvrir Python (en train de l'écrire depuis environ une heure) .

Le problème que j'ai est que le code que j'ai écrit ne fonctionnera que pour un seul dossier. Je peux voir pourquoi dans le code (voir #hardcoded path), je ne sais tout simplement pas comment je peux avancer avec Python car mon expérience avec ce dernier n’est que nouvelle.

Code 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()
156
Brock Woolf

Assurez-vous de bien comprendre les trois valeurs de retour de os.walk:

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

a la signification suivante:

  • root: chemin actuel "parcourant"
  • subdirs: Fichiers dans root du type répertoire
  • files: Fichiers dans root (pas dans subdirs) de type autre que répertoire

Et s'il vous plaît utilisez os.path.join au lieu de concaténer avec une barre oblique! Votre problème est filePath = rootdir + '/' + file - vous devez concaténer le dossier actuellement "parcouru" au lieu du dossier le plus haut. Donc, cela doit être filePath = os.path.join(root, file). BTW "fichier" est intégré, vous ne l'utilisez donc pas normalement comme nom de variable.

Un autre problème concerne vos boucles, qui devraient être comme ceci, par exemple:

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 vous ne le saviez pas, l'instruction with pour les fichiers est un raccourci:

with open('filename', 'rb') as f:
    dosomething()

# is effectively the same as

f = open('filename', 'rb')
try:
    dosomething()
finally:
    f.close()
276
AndiDog

Si vous utilisez Python 3.5 ou supérieur, vous pouvez le faire en 1 ligne.

import glob

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

Comme mentionné dans la documentation

Si récursif est vrai, le modèle '**' correspondra à tous les fichiers et à zéro ou plusieurs répertoires et sous-répertoires.

Si vous voulez tous les fichiers, vous pouvez utiliser

import glob

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

D'accord avec Dave Webb, os.walk donnera un élément pour chaque répertoire de l'arborescence. Le fait est que vous n'avez simplement pas à vous soucier de subFolders.

Un code comme celui-ci devrait fonctionner:

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())
33
Clément
import glob
import os

root_dir = <root_dir_here>

for filename in glob.iglob(root_dir + '**/**', recursive=True):
    if os.path.isfile(filename):
        with open(filename,'r') as file:
            print(file.read())

**/** est utilisé pour obtenir tous les fichiers récursivement, y compris directory.

if os.path.isfile(filename) est utilisé pour vérifier si la variable filename est file ou directory, si c'est un fichier, alors nous pouvons lire ce fichier. Ici, je suis en train d'imprimer un fichier.

4
Neeraj Sonaniya

utilisez os.path.join() pour construire vos chemins.

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()
3
ghostdog74

TL; DR: Ceci est l'équivalent de find -type f pour parcourir tous les fichiers dans tous les répertoires ci-dessous, y compris celui en cours:

for currentpath, dirs, files in os.walk('.'):
    for file in files:
        print(os.path.join(currentpath, file))

Comme déjà mentionné dans d'autres réponses, os.walk() est la réponse, mais elle pourrait être mieux expliquée. C'est assez simple! Marchons à travers cet arbre:

docs/
└── doc1.odt
pics/
todo.txt

Avec ce code:

for currentpath, folders, files in os.walk('.'):
    print(currentpath)

Le currentpath est le dossier actuel qu'il est en train de regarder. Cela produira:

.
./docs
./pics

Donc, il boucle trois fois, car il y a trois dossiers: le dossier en cours, docs et pics. Dans chaque boucle, il remplit les variables dirs et files avec tous les dossiers et fichiers. Montrons-leur:

for currentpath, folders, files in os.walk('.'):
    print(currentpath, dirs, files)

Cela nous montre:

# currentpath  folders           files
.              ['pics', 'docs']  ['todo.txt']
./pics         []                []
./docs         []                ['doc1.odt']

Ainsi, à la première ligne, nous voyons que nous sommes dans le dossier ., qu'il contient deux dossiers, à savoir pics et docs, et qu'il existe un fichier, à savoir todo.txt. . Vous n'avez rien à faire pour rentrer dans ces dossiers, car, comme vous le voyez, il est automatiquement récursif et ne vous donne que les fichiers des sous-dossiers. Et tous les sous-dossiers de celui-ci (bien que nous ne les ayons pas dans l'exemple).

Si vous voulez juste parcourir tous les fichiers, l'équivalent de find -type f, vous pouvez faire ceci:

for currentpath, dirs, files in os.walk('.'):
    for file in files:
        print(os.path.join(currentpath, file))

Cela génère:

./todo.txt
./docs/doc1.odt
2
Luc

Essaye ça:

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
1
Diego

Je pense que le problème est que vous ne traitez pas correctement la sortie de os.walk.

Tout d'abord, changez:

filePath = rootdir + '/' + file

à:

filePath = root + '/' + file

rootdir est votre répertoire de départ fixe; root est un répertoire renvoyé par os.walk.

Deuxièmement, vous n'avez pas besoin d'indenter votre boucle de traitement de fichier, car cela n'a aucun sens de l'exécuter pour chaque sous-répertoire. Vous aurez root défini dans chaque sous-répertoire. Vous n'avez pas besoin de traiter les sous-répertoires à la main, sauf si vous souhaitez utiliser les répertoires eux-mêmes.

0
Dave Webb

Si vous voulez une liste simple de tous les chemins sous un répertoire donné (comme find . dans le shell):

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

Pour inclure uniquement les chemins d'accès complets aux fichiers sous le répertoire de base, laissez + subdirs.

0
Scott Smith

os.walk fait la marche récursive par défaut. Pour chaque répertoire, en partant de la racine, le résultat est un triplet (répertoire, noms de répertoire, noms de fichiers)

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
0
b1r3k