Itérer dans les répertoires avec Python

158

J'ai besoin de parcourir les sous-répertoires d'un répertoire donné et de rechercher des fichiers. Si j'obtiens un fichier, je dois l'ouvrir, changer le contenu et le remplacer par mes propres lignes.

J'ai essayé ceci:

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

mais j'obtiens une erreur. Qu'est-ce que je fais mal?

Loup
la source
13
"Une erreur" - une erreur en particulier?
Daniel Roseman
1
Pourriez-vous expliquer un peu ce que vous espérez faire avec les fichiers / répertoires une fois que vous les aurez parcourus comme prévu? Veuillez également fournir les détails de l'erreur.
ChrisProsser
1
Le message d'erreur que j'obtiens est que le fichier cool.txt est introuvable. Dans mon dossier de test, j'ai un autre dossier appelé src et dans le dossier src j'ai un autre dossier appelé main, dans ce dossier j'ai cool.txt
Wolf
4
pouvez-vous simplement écrire l'erreur dans la question? c'est plus ennuyeux et inutile d'avoir à lire les commentaires pour le trouver.
Charlie Parker
1
plus d'un an plus tard, je ne peux pas croire que je demande à nouveau que l'erreur soit publiée @Wolf
Charlie Parker

Réponses:

301

Le parcours réel des répertoires fonctionne comme vous l'avez codé. Si vous remplacez le contenu de la boucle interne par une simple printinstruction, vous pouvez voir que chaque fichier est trouvé:

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 vous obtenez toujours des erreurs lors de l'exécution de ce qui précède, veuillez fournir le message d'erreur.


Mis à jour pour 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))
ChrisProsser
la source
1
C: / Users / sid / Desktop / test \ src \ app / cool.txt C: / Users / sid / Desktop / test \ src \ app / woohoo.txt Ya dans la déclaration ouverte de mon code, je pense que je dois donnez le chemin absolu du fichier. import os rootdir = 'C: / Users / spemmara / Desktop / test / src / app /' pour sous-répertoire, dirs, fichiers dans os.walk (rootdir): pour fichier dans fichiers: f = open (subdir + '/' + fichier , 'r') lines = f.readlines () f.close () f = open (subdir + '/' + file, 'w') pour la ligne dans les lignes: newline = "hey i know" f.write (newline) f.close () Merci mec. C'est résolu
Loup
3
Salut! Veuillez garder à l'esprit que "imprimer" en python 3 nécessite des parenthèses, sinon renvoie une erreur de syntaxe. J'espère que cela t'aides!
Tommaso Di Noto
14

Une autre façon de renvoyer tous les fichiers dans les sous-répertoires est d'utiliser le pathlibmodule , introduit dans Python 3.4, qui fournit une approche orientée objet pour gérer les chemins du système de fichiers (Pathlib est également disponible sur Python 2.7 via le module pathlib2 sur 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()]

Depuis Python 3.5, le globmodule prend également en charge la recherche récursive de fichiers:

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)]

L'une file_listou l'autre des approches ci-dessus peut être répétée sans avoir besoin d'une boucle imbriquée:

for f in file_list:
    print(f) # Replace with desired operations
joelostblom
la source
1
Qu'est-ce qui est préférable ici pour Python 3.6?
PhoenixDev
@PhoenixDev Je n'ai pas entendu parler d'une approche plutôt que de l'autre en général. Je préfère m'utiliser pathlibmoi-même, principalement parce que j'aime la syntaxe des méthodes orientées objet. Il existe d'autres différences, telles que la bibliothèque de chemins renvoie des classes de chemins spécifiques plutôt que des chaînes, et les fonctions disponibles diffèrent entre les bibliothèques (par exemple os.path.expanduser('~')vs Path.home()). Parcourez la documentation et voyez quelle approche vous préférez.
joelostblom
Au lieu d'ajouter **le modèle glob, vous pouvez utiliser rglob.
Georgy
12

Dès 2020 , glob.iglob(path/**, recursive=True)semble la solution la plus pythonique , à savoir:

import glob, os

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

Production:

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

Remarques:
1 - glob.iglob

glob.iglob(pathname, recursive=False)

Renvoie un itérateur qui donne les mêmes valeurs que glob()sans les stocker toutes simultanément.

2 - Si récursif est True, le modèle '**'correspondra à tous les fichiers et zéro ou plus directorieset subdirectories.

3 - Si le répertoire contient des fichiers commençant par,  .ils ne seront pas mis en correspondance par défaut. Par exemple, considérons un répertoire contenant  card.gif et .card.gif:

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

4 - Vous pouvez également utiliser rglob(pattern), ce qui équivaut glob() à appeler  avec **/ajouté devant le modèle relatif donné.

CONvid19
la source
1
Cette solution pythonique ne répertorie pas les fichiers cachés (aka dotfiles) alors que celui accepté le fait.
ashrasmun
@ashrasmun Ce que vous mentionnez est bien expliqué dans docs.python.org/3/library/glob.html
CONvid19