Répertoire, sous-répertoire et fichiers de la liste Python

130

J'essaye de créer un script pour lister tous les répertoires, sous-répertoires et fichiers dans un répertoire donné.
J'ai essayé ceci:

import sys,os

root = "/home/patate/directory/"
path = os.path.join(root, "targetdirectory")

for r,d,f in os.walk(path):
    for file in f:
        print os.path.join(root,file)

Malheureusement, cela ne fonctionne pas correctement.
J'obtiens tous les fichiers, mais pas leurs chemins complets.

Par exemple, si la structure dir serait:

/home/patate/directory/targetdirectory/123/456/789/file.txt

Il imprimerait:

/home/patate/directory/targetdirectory/file.txt

Ce dont j'ai besoin, c'est du premier résultat. Toute aide serait grandement appréciée! Merci.

thomytheyon
la source

Réponses:

225

Utilisez os.path.joinpour concaténer le répertoire et le nom du fichier :

for path, subdirs, files in os.walk(root):
    for name in files:
        print os.path.join(path, name)

Notez l'utilisation de pathet non rootdans la concaténation, car l'utilisation rootserait incorrecte.


Dans Python 3.4, le module pathlib a été ajouté pour faciliter les manipulations de chemin. Donc, l'équivalent de os.path.joinserait:

pathlib.PurePath(path, name)

L'avantage de pathlibest que vous pouvez utiliser une variété de méthodes utiles sur les chemins. Si vous utilisez la Pathvariante concrète, vous pouvez également effectuer des appels de système d'exploitation réels à travers eux, comme changer dans un répertoire, supprimer le chemin, ouvrir le fichier vers lequel il pointe et bien plus encore.

Eli Bendersky
la source
c'est la seule et unique réponse utile aux nombreuses questions qui ont été posées concernant "comment obtenir tous les fichiers récursivement en python".
harrisonfooord
liste de compréhension: all_files = [os.path.join (chemin, nom) pour le nom dans les fichiers pour le chemin, les sous-répertoires, les fichiers dans os.walk (dossier)]
Nir
En Python3, utilisez des parenthèses pour la fonction d'impressionprint(os.path.join(path, name))
Ehsan il y a
45

Juste au cas où ... Récupérer tous les fichiers du répertoire et des sous-répertoires correspondant à un modèle (* .py par exemple):

import os
from fnmatch import fnmatch

root = '/some/directory'
pattern = "*.py"

for path, subdirs, files in os.walk(root):
    for name in files:
        if fnmatch(name, pattern):
            print os.path.join(path, name)
Ivan
la source
10

Voici un one-liner:

import os

[val for sublist in [[os.path.join(i[0], j) for j in i[2]] for i in os.walk('./')] for val in sublist]
# Meta comment to ease selecting text

La val for sublist in ...boucle la plus externe aplatit la liste pour qu'elle soit unidimensionnelle. La jboucle recueille une liste de chaque nom de base de fichier et la joint au chemin actuel. Enfin, la iboucle itère sur tous les répertoires et sous-répertoires.

Cet exemple utilise le chemin d'accès codé ./en dur dans l' os.walk(...)appel, vous pouvez compléter n'importe quelle chaîne de chemin que vous souhaitez.

Remarque: os.path.expanduseret / ou os.path.expandvarspeut être utilisé pour des chaînes de chemins comme~/

Prolonger cet exemple:

Il est facile d'ajouter des tests de nom de base de fichier et des tests de nom de répertoire.

Par exemple, tester les *.jpgfichiers:

... for j in i[2] if j.endswith('.jpg')] ...

De plus, à l'exclusion du .gitrépertoire:

... for i in os.walk('./') if '.git' not in i[0].split('/')]
ThorSummoner
la source
Cela fonctionne, mais pour exclure .git directoy vous devez vérifier si '.git' n'est PAS dans le chemin.
Roman Rdgz
Oui. Devrait être si '.git' pas dans i [0] .split ('/')]
Roman Rdgz
Je recommanderais os.walkplutôt une boucle de répertoire manuel, les générateurs sont excellents, allez les utiliser.
ThorSummoner
9

Je ne pouvais pas commenter donc la réponse écrite ici. C'est la ligne la plus claire que j'ai vue:

import os
[os.path.join(path, name) for path, subdirs, files in os.walk(root) for name in files]
Mong H. Ng
la source
4

Vous pouvez jeter un œil à cet échantillon que j'ai réalisé. Il utilise la fonction os.path.walk qui est obsolète attention.Utilise une liste pour stocker tous les chemins de fichiers

root = "Your root directory"
ex = ".txt"
where_to = "Wherever you wanna write your file to"
def fileWalker(ext,dirname,names):
    '''
    checks files in names'''
    pat = "*" + ext[0]
    for f in names:
        if fnmatch.fnmatch(f,pat):
            ext[1].append(os.path.join(dirname,f))


def writeTo(fList):

    with open(where_to,"w") as f:
        for di_r in fList:
            f.write(di_r + "\n")






if __name__ == '__main__':
    li = []
    os.path.walk(root,fileWalker,[ex,li])

    writeTo(li)
devsaw
la source
4

One-liner un peu plus simple:

import os
from itertools import product, chain

chain.from_iterable([[os.sep.join(w) for w in product([i[0]], i[2])] for i in os.walk(dir)])
Daniel
la source
2

Puisque chaque exemple ici utilise simplement walk(avec join), je voudrais montrer un bel exemple et une comparaison avec listdir:

import os, time

def listFiles1(root): # listdir
    allFiles = []; walk = [root]
    while walk:
        folder = walk.pop(0)+"/"; items = os.listdir(folder) # items = folders + files
        for i in items: i=folder+i; (walk if os.path.isdir(i) else allFiles).append(i)
    return allFiles

def listFiles2(root): # listdir/join (takes ~1.4x as long) (and uses '\\' instead)
    allFiles = []; walk = [root]
    while walk:
        folder = walk.pop(0); items = os.listdir(folder) # items = folders + files
        for i in items: i=os.path.join(folder,i); (walk if os.path.isdir(i) else allFiles).append(i)
    return allFiles

def listFiles3(root): # walk (takes ~1.5x as long)
    allFiles = []
    for folder, folders, files in os.walk(root):
        for file in files: allFiles+=[folder.replace("\\","/")+"/"+file] # folder+"\\"+file still ~1.5x
    return allFiles

def listFiles4(root): # walk/join (takes ~1.6x as long) (and uses '\\' instead)
    allFiles = []
    for folder, folders, files in os.walk(root):
        for file in files: allFiles+=[os.path.join(folder,file)]
    return allFiles


for i in range(100): files = listFiles1("src") # warm up

start = time.time()
for i in range(100): files = listFiles1("src") # listdir
print("Time taken: %.2fs"%(time.time()-start)) # 0.28s

start = time.time()
for i in range(100): files = listFiles2("src") # listdir and join
print("Time taken: %.2fs"%(time.time()-start)) # 0.38s

start = time.time()
for i in range(100): files = listFiles3("src") # walk
print("Time taken: %.2fs"%(time.time()-start)) # 0.42s

start = time.time()
for i in range(100): files = listFiles4("src") # walk and join
print("Time taken: %.2fs"%(time.time()-start)) # 0.47s

Donc, comme vous pouvez le constater par vous-même, la listdirversion est beaucoup plus efficace. (et c'est joinlent)

Flaque
la source