Comment lister tous les fichiers d'un répertoire?

3473

Comment puis-je répertorier tous les fichiers d'un répertoire en Python et les ajouter à un list?

duhhunjonn
la source

Réponses:

4217

os.listdir()vous obtiendra tout ce qui est dans un répertoire - fichiers et répertoires .

Si vous voulez seulement des fichiers, vous pouvez soit filtrer cela en utilisant os.path:

from os import listdir
from os.path import isfile, join
onlyfiles = [f for f in listdir(mypath) if isfile(join(mypath, f))]

ou vous pouvez utiliser os.walk()qui donne deux listes pour chaque répertoire qu'il visite - division en fichiers et répertoires pour vous. Si vous ne voulez que le répertoire supérieur, vous pouvez simplement casser la première fois qu'il donne

from os import walk

f = []
for (dirpath, dirnames, filenames) in walk(mypath):
    f.extend(filenames)
    break
pycruft
la source
87
Un peu plus simple: (_, _, filenames) = walk(mypath).next() (si vous êtes sûr que la marche renverra au moins une valeur, ce qu'elle devrait.)
misterbee
9
Légère modification pour stocker les chemins complets: for (dirpath, dirnames, filenames) in os.walk (mypath): checksum_files.extend (os.path.join (dirpath, filename) for filename in filenames) break
okigan
150
f.extend(filenames)n'est pas réellement équivalent à f = f + filenames. extendmodifiera fsur place, tandis que l'ajout crée une nouvelle liste dans un nouvel emplacement de mémoire. Cela signifie extendest généralement plus efficace que +, mais cela peut parfois prêter à confusion si plusieurs objets contiennent des références à la liste. Enfin, il convient de noter que cela f += filenameséquivaut à f.extend(filenames), non f = f + filenames .
Benjamin Hodgson
30
@misterbee, votre solution est la meilleure, juste une petite amélioration:_, _, filenames = next(walk(mypath), (None, None, []))
bgusach
35
en utilisation python 3.x(_, _, filenames) = next(os.walk(mypath))
ET-CS
1684

Je préfère utiliser le globmodule, car il fait la correspondance et l'expansion des modèles.

import glob
print(glob.glob("/home/adam/*.txt"))

Il renverra une liste avec les fichiers interrogés:

['/home/adam/file1.txt', '/home/adam/file2.txt', .... ]
adamk
la source
17
c'est un raccourci pour listdir + fnmatch docs.python.org/library/fnmatch.html#fnmatch.fnmatch
Stefano
31
pour clarifier, cela ne renvoie pas le "chemin complet"; il renvoie simplement l'expansion du globe, quelle qu'elle soit. Par exemple, étant donné /home/user/foo/bar/hello.txt, si en cours d'exécution dans le répertoire foo, le glob("bar/*.txt")retourne bar/hello.txt. Il y a des cas où vous voulez en fait le chemin complet (c'est-à-dire absolu); pour ces cas, voir stackoverflow.com/questions/51520/…
michael
1
Connexes: recherchez des fichiers de manière récursive avec glob: stackoverflow.com/a/2186565/4561887
Gabriel Staples
6
ne répond pas à cette question. glob.glob("*")aurait.
Jean-François Fabre
beau!!!! alors .... x=glob.glob("../train/*.png")me donnera un tableau de mes chemins, tant que je connais le nom du dossier. Trop cool!
Jennifer Crosby
860

Obtenez une liste de fichiers avec Python 2 et 3


os.listdir()

Comment obtenir tous les fichiers (et répertoires) dans le répertoire courant (Python 3)

Voici des méthodes simples pour récupérer uniquement les fichiers dans le répertoire en cours, en utilisant os et la listdir()fonction, en Python 3. Une exploration plus approfondie, montrera comment retourner les dossiers dans le répertoire, mais vous n'aurez pas le fichier dans le sous-répertoire, pour cela vous peut utiliser la marche - discuté plus tard).

 import os
 arr = os.listdir()
 print(arr)

 >>> ['$RECYCLE.BIN', 'work.txt', '3ebooks.txt', 'documents']

glob

J'ai trouvé glob plus facile de sélectionner le fichier du même type ou avec quelque chose en commun. Regardez l'exemple suivant:

import glob

txtfiles = []
for file in glob.glob("*.txt"):
    txtfiles.append(file)

glob avec compréhension de liste

import glob

mylist = [f for f in glob.glob("*.txt")]

glob avec une fonction

La fonction renvoie une liste de l'extension donnée (.txt, .docx ecc.) Dans l'argument

import glob

def filebrowser(ext=""):
    "Returns files with an extension"
    return [f for f in glob.glob(f"*{ext}")]

x = filebrowser(".txt")
print(x)

>>> ['example.txt', 'fb.txt', 'intro.txt', 'help.txt']

glob étendre le code précédent

La fonction retourne maintenant une liste de fichiers correspondant à la chaîne que vous passez en argument

import glob

def filesearch(word=""):
    """Returns a list with all files with the word/extension in it"""
    file = []
    for f in glob.glob("*"):
        if word[0] == ".":
            if f.endswith(word):
                file.append(f)
                return file
        elif word in f:
            file.append(f)
            return file
    return file

lookfor = "example", ".py"
for w in lookfor:
    print(f"{w:10} found => {filesearch(w)}")

production

example    found => []
.py        found => ['search.py']

Obtention du nom de chemin complet avec os.path.abspath

Comme vous l'avez remarqué, vous n'avez pas le chemin complet du fichier dans le code ci-dessus. Si vous devez avoir le chemin absolu, vous pouvez utiliser une autre fonction du os.pathmodule appelé _getfullpathname, en plaçant le fichier dont vous obtenez os.listdir()comme argument. Il existe d'autres façons d'avoir le chemin complet, comme nous le verrons plus tard (j'ai remplacé, comme suggéré par mexmex, _getfullpathname avec abspath).

 import os
 files_path = [os.path.abspath(x) for x in os.listdir()]
 print(files_path)

 >>> ['F:\\documenti\applications.txt', 'F:\\documenti\collections.txt']

Obtenez le nom de chemin complet d'un type de fichier dans tous les sous-répertoires avec walk

Je trouve cela très utile pour trouver des choses dans de nombreux répertoires, et cela m'a aidé à trouver un fichier dont je ne me souvenais pas du nom:

import os

# Getting the current work directory (cwd)
thisdir = os.getcwd()

# r=root, d=directories, f = files
for r, d, f in os.walk(thisdir):
    for file in f:
        if file.endswith(".docx"):
            print(os.path.join(r, file))

os.listdir(): récupère les fichiers dans le répertoire courant (Python 2)

En Python 2, si vous voulez la liste des fichiers dans le répertoire courant, vous devez donner l'argument comme '.' ou os.getcwd () dans la méthode os.listdir.

 import os
 arr = os.listdir('.')
 print(arr)

 >>> ['$RECYCLE.BIN', 'work.txt', '3ebooks.txt', 'documents']

Pour remonter dans l'arborescence des répertoires

# Method 1
x = os.listdir('..')

# Method 2
x= os.listdir('/')

Récupérer des fichiers: os.listdir()dans un répertoire particulier (Python 2 et 3)

 import os
 arr = os.listdir('F:\\python')
 print(arr)

 >>> ['$RECYCLE.BIN', 'work.txt', '3ebooks.txt', 'documents']

Récupère les fichiers d'un sous-répertoire particulier avec os.listdir()

import os

x = os.listdir("./content")

os.walk('.') - répertoire actuel

 import os
 arr = next(os.walk('.'))[2]
 print(arr)

 >>> ['5bs_Turismo1.pdf', '5bs_Turismo1.pptx', 'esperienza.txt']

next(os.walk('.')) et os.path.join('dir', 'file')

 import os
 arr = []
 for d,r,f in next(os.walk("F:\\_python")):
     for file in f:
         arr.append(os.path.join(r,file))

 for f in arr:
     print(files)

>>> F:\\_python\\dict_class.py
>>> F:\\_python\\programmi.txt

next(os.walk('F:\\') - obtenir le chemin complet - liste de compréhension

 [os.path.join(r,file) for r,d,f in next(os.walk("F:\\_python")) for file in f]

 >>> ['F:\\_python\\dict_class.py', 'F:\\_python\\programmi.txt']

os.walk - obtenir le chemin complet - tous les fichiers dans les sous-répertoires **

x = [os.path.join(r,file) for r,d,f in os.walk("F:\\_python") for file in f]
print(x)

>>> ['F:\\_python\\dict.py', 'F:\\_python\\progr.txt', 'F:\\_python\\readl.py']

os.listdir() - obtenir uniquement des fichiers txt

 arr_txt = [x for x in os.listdir() if x.endswith(".txt")]
 print(arr_txt)

 >>> ['work.txt', '3ebooks.txt']

Utilisation globpour obtenir le chemin complet des fichiers

Si j'ai besoin du chemin absolu des fichiers:

from path import path
from glob import glob
x = [path(f).abspath() for f in glob("F:\\*.txt")]
for f in x:
    print(f)

>>> F:\acquistionline.txt
>>> F:\acquisti_2018.txt
>>> F:\bootstrap_jquery_ecc.txt

Utilisation os.path.isfilepour éviter les répertoires dans la liste

import os.path
listOfFiles = [f for f in os.listdir() if os.path.isfile(f)]
print(listOfFiles)

>>> ['a simple game.py', 'data.txt', 'decorator.py']

Utilisation pathlibde Python 3.4

import pathlib

flist = []
for p in pathlib.Path('.').iterdir():
    if p.is_file():
        print(p)
        flist.append(p)

 >>> error.PNG
 >>> exemaker.bat
 >>> guiprova.mp3
 >>> setup.py
 >>> speak_gui2.py
 >>> thumb.PNG

Avec list comprehension:

flist = [p for p in pathlib.Path('.').iterdir() if p.is_file()]

Vous pouvez également utiliser pathlib.Path()au lieu depathlib.Path(".")

Utilisez la méthode glob dans pathlib.Path ()

import pathlib

py = pathlib.Path().glob("*.py")
for file in py:
    print(file)

>>> stack_overflow_list.py
>>> stack_overflow_list_tkinter.py

Obtenez tous et seulement les fichiers avec os.walk

import os
x = [i[2] for i in os.walk('.')]
y=[]
for t in x:
    for f in t:
        y.append(f)
print(y)

>>> ['append_to_list.py', 'data.txt', 'data1.txt', 'data2.txt', 'data_180617', 'os_walk.py', 'READ2.py', 'read_data.py', 'somma_defaltdic.py', 'substitute_words.py', 'sum_data.py', 'data.txt', 'data1.txt', 'data_180617']

Récupère uniquement les fichiers avec next et marche dans un répertoire

 import os
 x = next(os.walk('F://python'))[2]
 print(x)

 >>> ['calculator.bat','calculator.py']

Obtenez uniquement les répertoires avec next et parcourez un répertoire

 import os
 next(os.walk('F://python'))[1] # for the current dir use ('.')

 >>> ['python3','others']

Obtenez tous les noms des sous-répertoires avec walk

for r,d,f in os.walk("F:\\_python"):
    for dirs in d:
        print(dirs)

>>> .vscode
>>> pyexcel
>>> pyschool.py
>>> subtitles
>>> _metaprogramming
>>> .ipynb_checkpoints

os.scandir() à partir de Python 3.5 et supérieur

import os
x = [f.name for f in os.scandir() if f.is_file()]
print(x)

>>> ['calculator.bat','calculator.py']

# Another example with scandir (a little variation from docs.python.org)
# This one is more efficient than os.listdir.
# In this case, it shows the files only in the current directory
# where the script is executed.

import os
with os.scandir() as i:
    for entry in i:
        if entry.is_file():
            print(entry.name)

>>> ebookmaker.py
>>> error.PNG
>>> exemaker.bat
>>> guiprova.mp3
>>> setup.py
>>> speakgui4.py
>>> speak_gui2.py
>>> speak_gui3.py
>>> thumb.PNG

Exemples:

Ex. 1: Combien de fichiers y a-t-il dans les sous-répertoires?

Dans cet exemple, nous recherchons le nombre de fichiers inclus dans tout le répertoire et ses sous-répertoires.

import os

def count(dir, counter=0):
    "returns number of files in dir and subdirs"
    for pack in os.walk(dir):
        for f in pack[2]:
            counter += 1
    return dir + " : " + str(counter) + "files"

print(count("F:\\python"))

>>> 'F:\\\python' : 12057 files'

Ex.2: Comment copier tous les fichiers d'un répertoire vers un autre?

Un script pour mettre de l'ordre dans votre ordinateur en trouvant tous les fichiers d'un type (par défaut: pptx) et en les copiant dans un nouveau dossier.

import os
import shutil
from path import path

destination = "F:\\file_copied"
# os.makedirs(destination)

def copyfile(dir, filetype='pptx', counter=0):
    "Searches for pptx (or other - pptx is the default) files and copies them"
    for pack in os.walk(dir):
        for f in pack[2]:
            if f.endswith(filetype):
                fullpath = pack[0] + "\\" + f
                print(fullpath)
                shutil.copy(fullpath, destination)
                counter += 1
    if counter > 0:
        print('-' * 30)
        print("\t==> Found in: `" + dir + "` : " + str(counter) + " files\n")

for dir in os.listdir():
    "searches for folders that starts with `_`"
    if dir[0] == '_':
        # copyfile(dir, filetype='pdf')
        copyfile(dir, filetype='txt')


>>> _compiti18\Compito Contabilità 1\conti.txt
>>> _compiti18\Compito Contabilità 1\modula4.txt
>>> _compiti18\Compito Contabilità 1\moduloa4.txt
>>> ------------------------
>>> ==> Found in: `_compiti18` : 3 files

Ex. 3: Comment obtenir tous les fichiers dans un fichier txt

Dans le cas où vous souhaitez créer un fichier txt avec tous les noms de fichiers:

import os
mylist = ""
with open("filelist.txt", "w", encoding="utf-8") as file:
    for eachfile in os.listdir():
        mylist += eachfile + "\n"
    file.write(mylist)

Exemple: txt avec tous les fichiers d'un disque dur

"""
We are going to save a txt file with all the files in your directory.
We will use the function walk()
"""

import os

# see all the methods of os
# print(*dir(os), sep=", ")
listafile = []
percorso = []
with open("lista_file.txt", "w", encoding='utf-8') as testo:
    for root, dirs, files in os.walk("D:\\"):
        for file in files:
            listafile.append(file)
            percorso.append(root + "\\" + file)
            testo.write(file + "\n")
listafile.sort()
print("N. of files", len(listafile))
with open("lista_file_ordinata.txt", "w", encoding="utf-8") as testo_ordinato:
    for file in listafile:
        testo_ordinato.write(file + "\n")

with open("percorso.txt", "w", encoding="utf-8") as file_percorso:
    for file in percorso:
        file_percorso.write(file + "\n")

os.system("lista_file.txt")
os.system("lista_file_ordinata.txt")
os.system("percorso.txt")

Tout le fichier de C: \ dans un fichier texte

Il s'agit d'une version plus courte du code précédent. Modifiez le dossier où commencer à rechercher les fichiers si vous devez commencer à partir d'une autre position. Ce code génère un fichier texte de 50 Mo sur mon ordinateur avec quelque chose de moins de 500 000 lignes avec des fichiers avec le chemin complet.

import os

with open("file.txt", "w", encoding="utf-8") as filewrite:
    for r, d, f in os.walk("C:\\"):
        for file in f:
            filewrite.write(f"{r + file}\n")

Comment écrire un fichier avec tous les chemins dans un dossier d'un type

Avec cette fonction, vous pouvez créer un fichier txt qui aura le nom d'un type de fichier que vous recherchez (ex. Pngfile.txt) avec tout le chemin complet de tous les fichiers de ce type. Cela peut être utile parfois, je pense.

import os

def searchfiles(extension='.ttf', folder='H:\\'):
    "Create a txt file with all the file of a type"
    with open(extension[1:] + "file.txt", "w", encoding="utf-8") as filewrite:
        for r, d, f in os.walk(folder):
            for file in f:
                if file.endswith(extension):
                    filewrite.write(f"{r + file}\n")

# looking for png file (fonts) in the hard disk H:\
searchfiles('.png', 'H:\\')

>>> H:\4bs_18\Dolphins5.png
>>> H:\4bs_18\Dolphins6.png
>>> H:\4bs_18\Dolphins7.png
>>> H:\5_18\marketing html\assets\imageslogo2.png
>>> H:\7z001.png
>>> H:\7z002.png

(Nouveau) Trouvez tous les fichiers et ouvrez-les avec l'interface graphique de tkinter

Je voulais juste ajouter dans cette 2019 une petite application pour rechercher tous les fichiers dans un répertoire et pouvoir les ouvrir en double-cliquant sur le nom du fichier dans la liste. entrez la description de l'image ici

import tkinter as tk
import os

def searchfiles(extension='.txt', folder='H:\\'):
    "insert all files in the listbox"
    for r, d, f in os.walk(folder):
        for file in f:
            if file.endswith(extension):
                lb.insert(0, r + "\\" + file)

def open_file():
    os.startfile(lb.get(lb.curselection()[0]))

root = tk.Tk()
root.geometry("400x400")
bt = tk.Button(root, text="Search", command=lambda:searchfiles('.png', 'H:\\'))
bt.pack()
lb = tk.Listbox(root)
lb.pack(fill="both", expand=1)
lb.bind("<Double-Button>", lambda x: open_file())
root.mainloop()
Giovanni G. PY
la source
14
Ceci est un méli-mélo de trop de réponses aux questions non posées ici. Il peut également être utile d'expliquer quelles sont les mises en garde ou les approches recommandées. Je ne suis pas mieux de savoir une façon contre 20 façons de faire la même chose, sauf si je sais aussi laquelle est la plus appropriée à utiliser quand.
cs95
Ok, dès que possible, je vais jeter un coup d'œil à ma réponse et essayer de la rendre plus propre et avec des informations plus utiles sur la différence entre les méthodes, etc.
Giovanni G. PY
Vous ne devez pas déterminer l'extension du fichier en vérifiant si le nom de fichier contient une sous-chaîne. Cela pourrait causer de nombreux problèmes. Je recommande de toujours vérifier si le nom de fichier se termine par la sous-chaîne particulière.
ni1ight
Ok, @ n1light j'ai changé le code ...
Giovanni G. PY
812
import os
os.listdir("somedirectory")

renverra une liste de tous les fichiers et répertoires dans "somedirectory".

sepp2k
la source
11
Cela renvoie le chemin relatif des fichiers, par rapport au chemin complet renvoyé parglob.glob
xji
22
@JIXiang: os.listdir()renvoie toujours de simples noms de fichiers (pas des chemins relatifs). Ce qui glob.glob()retourne est déterminé par le format de chemin du modèle d'entrée.
mklement0
os.listdir () -> Il répertorie toujours le répertoire et le fichier à l'intérieur de l'emplacement fourni. Existe-t-il un moyen de répertorier uniquement le répertoire et non les fichiers?
RonyA
160

Une solution en ligne pour obtenir uniquement la liste des fichiers (pas de sous-répertoires):

filenames = next(os.walk(path))[2]

ou chemins absolus:

paths = [os.path.join(path, fn) for fn in next(os.walk(path))[2]]
Rémi
la source
7
Un seul revêtement si vous l'avez déjà fait import os. Semble moins concis qu'à glob()moi.
ArtOfWarfare
4
le problème avec glob est qu'un dossier appelé 'something.something' serait retourné par glob ('/ home / adam /*.*')
Remi
6
Sur OS X, il y a quelque chose appelé un bundle. C'est un répertoire qui devrait généralement être traité comme un fichier (comme un .tar). Souhaitez-vous que ceux-ci soient traités comme un fichier ou un répertoire? Utiliser glob()le traiterait comme un fichier. Votre méthode le traiterait comme un répertoire.
ArtOfWarfare
132

Obtention de chemins de fichiers complets à partir d'un répertoire et de tous ses sous-répertoires

import os

def get_filepaths(directory):
    """
    This function will generate the file names in a directory 
    tree by walking the tree either top-down or bottom-up. For each 
    directory in the tree rooted at directory top (including top itself), 
    it yields a 3-tuple (dirpath, dirnames, filenames).
    """
    file_paths = []  # List which will store all of the full filepaths.

    # Walk the tree.
    for root, directories, files in os.walk(directory):
        for filename in files:
            # Join the two strings in order to form the full filepath.
            filepath = os.path.join(root, filename)
            file_paths.append(filepath)  # Add it to the list.

    return file_paths  # Self-explanatory.

# Run the above function and store its results in a variable.   
full_file_paths = get_filepaths("/Users/johnny/Desktop/TEST")

  • Le chemin que j'ai fourni dans la fonction ci-dessus contenait 3 fichiers - deux d'entre eux dans le répertoire racine et un autre dans un sous-dossier appelé "SUBFOLDER". Vous pouvez maintenant faire des choses comme:
  • print full_file_paths qui imprimera la liste:

    • ['/Users/johnny/Desktop/TEST/file1.txt', '/Users/johnny/Desktop/TEST/file2.txt', '/Users/johnny/Desktop/TEST/SUBFOLDER/file3.dat']

Si vous le souhaitez, vous pouvez ouvrir et lire le contenu, ou vous concentrer uniquement sur les fichiers avec l'extension ".dat" comme dans le code ci-dessous:

for f in full_file_paths:
  if f.endswith(".dat"):
    print f

/Users/johnny/Desktop/TEST/SUBFOLDER/file3.dat

Johnny
la source
C'est la seule et unique réponse.
gagnant le
78

Depuis la version 3.4, il existe des itérateurs intégrés pour cela qui sont beaucoup plus efficaces que os.listdir():

pathlib: Nouveau dans la version 3.4.

>>> import pathlib
>>> [p for p in pathlib.Path('.').iterdir() if p.is_file()]

Selon PEP 428 , l'objectif de la pathlibbibliothèque est de fournir une hiérarchie simple de classes pour gérer les chemins de système de fichiers et les opérations courantes que les utilisateurs effectuent sur eux.

os.scandir(): Nouveau dans la version 3.5.

>>> import os
>>> [entry for entry in os.scandir('.') if entry.is_file()]

Notez que os.walk()utilise os.scandir()au lieu deos.listdir() version 3.5, et sa vitesse a été augmentée de 2 à 20 fois selon le PEP 471 .

Permettez-moi également de lire le commentaire de ShadowRanger ci-dessous.

SzieberthAdam
la source
1
Merci! Je pense que c'est la seule solution qui ne revient pas directement a list. Pourrait utiliser à la p.nameplace du premier palternativement si vous préférez.
jeromej
1
Bienvenue! Je préférerais générer des pathlib.Path()instances car elles ont de nombreuses méthodes utiles que je ne voudrais pas gaspiller. Vous pouvez également faire appel str(p)à eux pour les noms de chemin.
SzieberthAdam
6
Remarque: La os.scandirsolution sera plus efficace os.listdirqu'avec une os.path.is_filevérification ou similaire, même si vous en avez besoin list(donc vous ne bénéficiez pas d'une itération paresseuse), car os.scandirutilise des API fournies par le système d'exploitation qui vous donnent les is_fileinformations gratuitement pendant l'itération. , pas par fichier aller - retour vers le disque statdu tout (sous Windows, les DirEntrys vous obtenez complète statinformation gratuitement, sur les systèmes * NIX il doit statpour plus d' informations au - delà is_file, is_dir, etc., mais les DirEntrycaches sur la première statpour des raisons pratiques).
ShadowRanger
1
Vous pouvez également utiliser entry.namepour obtenir uniquement le nom du fichier ou entry.pathpour obtenir son chemin complet. Plus d'os.path.join () partout.
user136036
56

Notes préliminaires

  • Bien qu'il y ait une différenciation claire entre les termes de fichier et de répertoire dans le texte de la question, certains peuvent affirmer que les répertoires sont en fait des fichiers spéciaux
  • La déclaration: " tous les fichiers d'un répertoire " peut être interprétée de deux manières:
    1. Tous les descendants directs (ou niveau 1) uniquement
    2. Tous les descendants de l'arborescence complète des répertoires (y compris ceux des sous-répertoires)
  • Lorsque la question a été posée, j'imagine que Python 2 était la version LTS , mais les exemples de code seront exécutés par Python 3 ( .5 ) (je les garderai aussi conformes que possible à Python 2 ; aussi, tout code appartenant à Python que je vais publier est de la v3.5.4 - sauf indication contraire). Cela a des conséquences liées à un autre mot-clé dans la question: " ajoutez-les dans une liste ":

    • En pré versions Python 2.2 , les séquences (itérables) étaient principalement représentées par des listes (tuples, sets, ...)
    • En Python 2.2 , le concept de générateur ( [Python.Wiki]: Generators ) - avec l'aimable autorisation de [Python 3]: la déclaration de rendement ) - a été introduit. Au fil du temps, les homologues du générateur ont commencé à apparaître pour les fonctions qui retournaient / fonctionnaient avec des listes
    • En Python 3 , le générateur est le comportement par défaut
    • Je ne sais pas si le retour d'une liste est toujours obligatoire (ou un générateur ferait de même), mais le passage d'un générateur au constructeur de liste en créera une liste (et la consommera également). L'exemple ci-dessous illustre les différences sur [Python 3]: map ( fonction, itérable, ... )
    >>> import sys
    >>> sys.version
    '2.7.10 (default, Mar  8 2016, 15:02:46) [MSC v.1600 64 bit (AMD64)]'
    >>> m = map(lambda x: x, [1, 2, 3])  # Just a dummy lambda function
    >>> m, type(m)
    ([1, 2, 3], <type 'list'>)
    >>> len(m)
    3


    >>> import sys
    >>> sys.version
    '3.5.4 (v3.5.4:3f56838, Aug  8 2017, 02:17:05) [MSC v.1900 64 bit (AMD64)]'
    >>> m = map(lambda x: x, [1, 2, 3])
    >>> m, type(m)
    (<map object at 0x000001B4257342B0>, <class 'map'>)
    >>> len(m)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: object of type 'map' has no len()
    >>> lm0 = list(m)  # Build a list from the generator
    >>> lm0, type(lm0)
    ([1, 2, 3], <class 'list'>)
    >>>
    >>> lm1 = list(m)  # Build a list from the same generator
    >>> lm1, type(lm1)  # Empty list now - generator already consumed
    ([], <class 'list'>)
  • Les exemples seront basés sur un répertoire appelé root_dir avec la structure suivante (cet exemple est pour Win , mais j'utilise également la même arborescence sur Lnx ):

    E:\Work\Dev\StackOverflow\q003207219>tree /f "root_dir"
    Folder PATH listing for volume Work
    Volume serial number is 00000029 3655:6FED
    E:\WORK\DEV\STACKOVERFLOW\Q003207219\ROOT_DIR
    ¦   file0
    ¦   file1
    ¦
    +---dir0
    ¦   +---dir00
    ¦   ¦   ¦   file000
    ¦   ¦   ¦
    ¦   ¦   +---dir000
    ¦   ¦           file0000
    ¦   ¦
    ¦   +---dir01
    ¦   ¦       file010
    ¦   ¦       file011
    ¦   ¦
    ¦   +---dir02
    ¦       +---dir020
    ¦           +---dir0200
    +---dir1
    ¦       file10
    ¦       file11
    ¦       file12
    ¦
    +---dir2
    ¦   ¦   file20
    ¦   ¦
    ¦   +---dir20
    ¦           file200
    ¦
    +---dir3


Solutions

Approches programmatiques:

  1. [Python 3]: os. listdir ( path = '.' )

    Renvoie une liste contenant les noms des entrées du répertoire donnés par path. La liste est dans un ordre arbitraire et ne comprend pas les entrées spéciales '.'et '..'...


    >>> import os
    >>> root_dir = "root_dir"  # Path relative to current dir (os.getcwd())
    >>>
    >>> os.listdir(root_dir)  # List all the items in root_dir
    ['dir0', 'dir1', 'dir2', 'dir3', 'file0', 'file1']
    >>>
    >>> [item for item in os.listdir(root_dir) if os.path.isfile(os.path.join(root_dir, item))]  # Filter items and only keep files (strip out directories)
    ['file0', 'file1']

    Un exemple plus élaboré ( code_os_listdir.py ):

    import os
    from pprint import pformat
    
    
    def _get_dir_content(path, include_folders, recursive):
        entries = os.listdir(path)
        for entry in entries:
            entry_with_path = os.path.join(path, entry)
            if os.path.isdir(entry_with_path):
                if include_folders:
                    yield entry_with_path
                if recursive:
                    for sub_entry in _get_dir_content(entry_with_path, include_folders, recursive):
                        yield sub_entry
            else:
                yield entry_with_path
    
    
    def get_dir_content(path, include_folders=True, recursive=True, prepend_folder_name=True):
        path_len = len(path) + len(os.path.sep)
        for item in _get_dir_content(path, include_folders, recursive):
            yield item if prepend_folder_name else item[path_len:]
    
    
    def _get_dir_content_old(path, include_folders, recursive):
        entries = os.listdir(path)
        ret = list()
        for entry in entries:
            entry_with_path = os.path.join(path, entry)
            if os.path.isdir(entry_with_path):
                if include_folders:
                    ret.append(entry_with_path)
                if recursive:
                    ret.extend(_get_dir_content_old(entry_with_path, include_folders, recursive))
            else:
                ret.append(entry_with_path)
        return ret
    
    
    def get_dir_content_old(path, include_folders=True, recursive=True, prepend_folder_name=True):
        path_len = len(path) + len(os.path.sep)
        return [item if prepend_folder_name else item[path_len:] for item in _get_dir_content_old(path, include_folders, recursive)]
    
    
    def main():
        root_dir = "root_dir"
        ret0 = get_dir_content(root_dir, include_folders=True, recursive=True, prepend_folder_name=True)
        lret0 = list(ret0)
        print(ret0, len(lret0), pformat(lret0))
        ret1 = get_dir_content_old(root_dir, include_folders=False, recursive=True, prepend_folder_name=False)
        print(len(ret1), pformat(ret1))
    
    
    if __name__ == "__main__":
        main()

    Remarques :

    • Il existe deux implémentations:
      • Celui qui utilise des générateurs (bien sûr ici cela semble inutile, puisque je convertis immédiatement le résultat en liste)
      • Le classique (noms de fonctions se terminant par _old )
    • La récursivité est utilisée (pour entrer dans les sous-répertoires)
    • Pour chaque implémentation, il existe deux fonctions:
      • Celui qui commence par un trait de soulignement ( _ ): "privé" (ne doit pas être appelé directement) - qui fait tout le travail
      • Le public (wrapper sur le précédent): il supprime simplement le chemin initial (si nécessaire) des entrées retournées. C'est une implémentation moche, mais c'est la seule idée avec laquelle je pourrais venir à ce stade
    • En termes de performances, les générateurs sont généralement un peu plus rapides (considérant à la fois la création et l' itération ), mais je ne les ai pas testés dans les fonctions récursives, et j'itère également à l'intérieur de la fonction par rapport aux générateurs internes - je ne sais pas comment les performances amical est que
    • Jouez avec les arguments pour obtenir des résultats différents


    Sortie :

    (py35x64_test) E:\Work\Dev\StackOverflow\q003207219>"e:\Work\Dev\VEnvs\py35x64_test\Scripts\python.exe" "code_os_listdir.py"
    <generator object get_dir_content at 0x000001BDDBB3DF10> 22 ['root_dir\\dir0',
     'root_dir\\dir0\\dir00',
     'root_dir\\dir0\\dir00\\dir000',
     'root_dir\\dir0\\dir00\\dir000\\file0000',
     'root_dir\\dir0\\dir00\\file000',
     'root_dir\\dir0\\dir01',
     'root_dir\\dir0\\dir01\\file010',
     'root_dir\\dir0\\dir01\\file011',
     'root_dir\\dir0\\dir02',
     'root_dir\\dir0\\dir02\\dir020',
     'root_dir\\dir0\\dir02\\dir020\\dir0200',
     'root_dir\\dir1',
     'root_dir\\dir1\\file10',
     'root_dir\\dir1\\file11',
     'root_dir\\dir1\\file12',
     'root_dir\\dir2',
     'root_dir\\dir2\\dir20',
     'root_dir\\dir2\\dir20\\file200',
     'root_dir\\dir2\\file20',
     'root_dir\\dir3',
     'root_dir\\file0',
     'root_dir\\file1']
    11 ['dir0\\dir00\\dir000\\file0000',
     'dir0\\dir00\\file000',
     'dir0\\dir01\\file010',
     'dir0\\dir01\\file011',
     'dir1\\file10',
     'dir1\\file11',
     'dir1\\file12',
     'dir2\\dir20\\file200',
     'dir2\\file20',
     'file0',
     'file1']


  1. [Python 3]: os. scandir ( path = '.' ) ( Python 3.5 +, backport: [PyPI]: scandir )

    Renvoie un itérateur d' objets os.DirEntry correspondant aux entrées du répertoire données par path . Les entrées sont dans un ordre arbitraire ont produit, et les entrées spéciales '.'et '..'ne sont pas inclus.

    L'utilisation de scandir () au lieu de listdir () peut augmenter considérablement les performances du code qui nécessite également des informations sur le type ou l'attribut de fichier, car les objets os.DirEntry exposent ces informations si le système d'exploitation les fournit lors de l'analyse d'un répertoire. Toutes les méthodes os.DirEntry peuvent effectuer un appel système, mais is_dir () et is_file () nécessitent généralement un appel système uniquement pour les liens symboliques; os.DirEntry.stat () nécessite toujours un appel système sous Unix mais n'en requiert qu'un pour les liens symboliques sous Windows.


    >>> import os
    >>> root_dir = os.path.join(".", "root_dir")  # Explicitly prepending current directory
    >>> root_dir
    '.\\root_dir'
    >>>
    >>> scandir_iterator = os.scandir(root_dir)
    >>> scandir_iterator
    <nt.ScandirIterator object at 0x00000268CF4BC140>
    >>> [item.path for item in scandir_iterator]
    ['.\\root_dir\\dir0', '.\\root_dir\\dir1', '.\\root_dir\\dir2', '.\\root_dir\\dir3', '.\\root_dir\\file0', '.\\root_dir\\file1']
    >>>
    >>> [item.path for item in scandir_iterator]  # Will yield an empty list as it was consumed by previous iteration (automatically performed by the list comprehension)
    []
    >>>
    >>> scandir_iterator = os.scandir(root_dir)  # Reinitialize the generator
    >>> for item in scandir_iterator :
    ...     if os.path.isfile(item.path):
    ...             print(item.name)
    ...
    file0
    file1

    Remarques :

    • C'est similaire à os.listdir
    • Mais il est également plus flexible (et offre plus de fonctionnalités), plus de Python ic (et dans certains cas, plus rapide)


  1. [Python 3]: os. marcher ( top, topdown = True, onerror = None, followlinks = False )

    Générez les noms de fichiers dans une arborescence de répertoires en parcourant l'arborescence de haut en bas ou de bas en haut. Pour chaque répertoire dans l'arbre dont la racine répertoire haut (y compris haut lui - même), il donne un 3-tuple ( dirpath, dirnames, filenames).


    >>> import os
    >>> root_dir = os.path.join(os.getcwd(), "root_dir")  # Specify the full path
    >>> root_dir
    'E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir'
    >>>
    >>> walk_generator = os.walk(root_dir)
    >>> root_dir_entry = next(walk_generator)  # First entry corresponds to the root dir (passed as an argument)
    >>> root_dir_entry
    ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir', ['dir0', 'dir1', 'dir2', 'dir3'], ['file0', 'file1'])
    >>>
    >>> root_dir_entry[1] + root_dir_entry[2]  # Display dirs and files (direct descendants) in a single list
    ['dir0', 'dir1', 'dir2', 'dir3', 'file0', 'file1']
    >>>
    >>> [os.path.join(root_dir_entry[0], item) for item in root_dir_entry[1] + root_dir_entry[2]]  # Display all the entries in the previous list by their full path
    ['E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir0', 'E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir1', 'E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir2', 'E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir3', 'E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\file0', 'E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\file1']
    >>>
    >>> for entry in walk_generator:  # Display the rest of the elements (corresponding to every subdir)
    ...     print(entry)
    ...
    ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir0', ['dir00', 'dir01', 'dir02'], [])
    ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir0\\dir00', ['dir000'], ['file000'])
    ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir0\\dir00\\dir000', [], ['file0000'])
    ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir0\\dir01', [], ['file010', 'file011'])
    ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir0\\dir02', ['dir020'], [])
    ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir0\\dir02\\dir020', ['dir0200'], [])
    ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir0\\dir02\\dir020\\dir0200', [], [])
    ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir1', [], ['file10', 'file11', 'file12'])
    ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir2', ['dir20'], ['file20'])
    ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir2\\dir20', [], ['file200'])
    ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir3', [], [])

    Remarques :

    • Sous les scènes, il utilise os.scandir ( os.listdirsur les anciennes versions)
    • Il fait le gros du travail en se reproduisant dans les sous-dossiers


  1. [Python 3]: glob. glob ( nom de chemin, *, récursif = Faux ) ( [Python 3]: glob. iglob ( nom de chemin, *, récursif = Faux) ) )

    Renvoie une liste éventuellement vide de noms de chemins correspondant à chemin d'accès , qui doit être une chaîne contenant une spécification de chemin. chemin peut être absolu (comme /usr/src/Python-1.5/Makefile) ou relatif (comme ../../Tools/*/*.gif), et peut contenir des caractères génériques de style shell. Les liens symboliques brisés sont inclus dans les résultats (comme dans le shell).
    ...
    Modifié dans la version 3.5 : Prise en charge des globes récursifs à l'aide de « **».


    >>> import glob, os
    >>> wildcard_pattern = "*"
    >>> root_dir = os.path.join("root_dir", wildcard_pattern)  # Match every file/dir name
    >>> root_dir
    'root_dir\\*'
    >>>
    >>> glob_list = glob.glob(root_dir)
    >>> glob_list
    ['root_dir\\dir0', 'root_dir\\dir1', 'root_dir\\dir2', 'root_dir\\dir3', 'root_dir\\file0', 'root_dir\\file1']
    >>>
    >>> [item.replace("root_dir" + os.path.sep, "") for item in glob_list]  # Strip the dir name and the path separator from begining
    ['dir0', 'dir1', 'dir2', 'dir3', 'file0', 'file1']
    >>>
    >>> for entry in glob.iglob(root_dir + "*", recursive=True):
    ...     print(entry)
    ...
    root_dir\
    root_dir\dir0
    root_dir\dir0\dir00
    root_dir\dir0\dir00\dir000
    root_dir\dir0\dir00\dir000\file0000
    root_dir\dir0\dir00\file000
    root_dir\dir0\dir01
    root_dir\dir0\dir01\file010
    root_dir\dir0\dir01\file011
    root_dir\dir0\dir02
    root_dir\dir0\dir02\dir020
    root_dir\dir0\dir02\dir020\dir0200
    root_dir\dir1
    root_dir\dir1\file10
    root_dir\dir1\file11
    root_dir\dir1\file12
    root_dir\dir2
    root_dir\dir2\dir20
    root_dir\dir2\dir20\file200
    root_dir\dir2\file20
    root_dir\dir3
    root_dir\file0
    root_dir\file1

    Remarques :

    • Les usages os.listdir
    • Pour les grands arbres (surtout si récursif est activé ), l' iglob est préféré
    • Permet un filtrage avancé basé sur le nom (en raison du caractère générique)


  1. [Python 3]: class pathlib. Path ( * pathsegments ) ( Python 3.4 +, backport: [PyPI]: pathlib2 )

    >>> import pathlib
    >>> root_dir = "root_dir"
    >>> root_dir_instance = pathlib.Path(root_dir)
    >>> root_dir_instance
    WindowsPath('root_dir')
    >>> root_dir_instance.name
    'root_dir'
    >>> root_dir_instance.is_dir()
    True
    >>>
    >>> [item.name for item in root_dir_instance.glob("*")]  # Wildcard searching for all direct descendants
    ['dir0', 'dir1', 'dir2', 'dir3', 'file0', 'file1']
    >>>
    >>> [os.path.join(item.parent.name, item.name) for item in root_dir_instance.glob("*") if not item.is_dir()]  # Display paths (including parent) for files only
    ['root_dir\\file0', 'root_dir\\file1']

    Remarques :

    • C'est une façon d'atteindre notre objectif
    • C'est le style OOP de gestion des chemins
    • Offre beaucoup de fonctionnalités


  1. [Python 2]: dircache.listdir (chemin) ( Python 2 uniquement)


    def listdir(path):
        """List directory contents, using cache."""
        try:
            cached_mtime, list = cache[path]
            del cache[path]
        except KeyError:
            cached_mtime, list = -1, []
        mtime = os.stat(path).st_mtime
        if mtime != cached_mtime:
            list = os.listdir(path)
            list.sort()
        cache[path] = mtime, list
        return list


  1. [man7]: OPENDIR (3) / [man7]: READDIR (3) / [man7]: CLOSEDIR (3) via [Python 3]: ctypes - Une bibliothèque de fonctions étrangères pour Python ( spécifique POSIX )

    ctypes est une bibliothèque de fonctions étrangère pour Python. Il fournit des types de données compatibles C et permet d'appeler des fonctions dans des DLL ou des bibliothèques partagées. Il peut être utilisé pour envelopper ces bibliothèques en Python pur.

    code_ctypes.py :

    #!/usr/bin/env python3
    
    import sys
    from ctypes import Structure, \
        c_ulonglong, c_longlong, c_ushort, c_ubyte, c_char, c_int, \
        CDLL, POINTER, \
        create_string_buffer, get_errno, set_errno, cast
    
    
    DT_DIR = 4
    DT_REG = 8
    
    char256 = c_char * 256
    
    
    class LinuxDirent64(Structure):
        _fields_ = [
            ("d_ino", c_ulonglong),
            ("d_off", c_longlong),
            ("d_reclen", c_ushort),
            ("d_type", c_ubyte),
            ("d_name", char256),
        ]
    
    LinuxDirent64Ptr = POINTER(LinuxDirent64)
    
    libc_dll = this_process = CDLL(None, use_errno=True)
    # ALWAYS set argtypes and restype for functions, otherwise it's UB!!!
    opendir = libc_dll.opendir
    readdir = libc_dll.readdir
    closedir = libc_dll.closedir
    
    
    def get_dir_content(path):
        ret = [path, list(), list()]
        dir_stream = opendir(create_string_buffer(path.encode()))
        if (dir_stream == 0):
            print("opendir returned NULL (errno: {:d})".format(get_errno()))
            return ret
        set_errno(0)
        dirent_addr = readdir(dir_stream)
        while dirent_addr:
            dirent_ptr = cast(dirent_addr, LinuxDirent64Ptr)
            dirent = dirent_ptr.contents
            name = dirent.d_name.decode()
            if dirent.d_type & DT_DIR:
                if name not in (".", ".."):
                    ret[1].append(name)
            elif dirent.d_type & DT_REG:
                ret[2].append(name)
            dirent_addr = readdir(dir_stream)
        if get_errno():
            print("readdir returned NULL (errno: {:d})".format(get_errno()))
        closedir(dir_stream)
        return ret
    
    
    def main():
        print("{:s} on {:s}\n".format(sys.version, sys.platform))
        root_dir = "root_dir"
        entries = get_dir_content(root_dir)
        print(entries)
    
    
    if __name__ == "__main__":
        main()

    Remarques :

    • Il charge les trois fonctions de libc (chargées dans le processus actuel) et les appelle (pour plus de détails, vérifiez [SO]: Comment puis-je vérifier si un fichier existe sans exceptions? (@ Réponse de CristiFati) - dernières notes de l'élément # 4. ). Cela placerait cette approche très près du bord Python / C
    • LinuxDirent64 est la représentation ctypes de struct dirent64 de [man7]: dirent.h (0P) (tout comme les constantes DT_ ) de ma machine: Ubtu 16 x64 ( 4.10.0-40-generic et libc6-dev: amd64 ). Sur d'autres versions / versions, la définition de la structure peut différer, et si c'est le cas, l' alias ctypes doit être mis à jour, sinon cela produira un comportement indéfini
    • Il renvoie des données dans le os.walk format. Je n'ai pas pris la peine de le rendre récursif, mais à partir du code existant, ce serait une tâche assez banale
    • Tout est également faisable sur Win , les données (bibliothèques, fonctions, structures, constantes, ...) diffèrent


    Sortie :

    [cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q003207219]> ./code_ctypes.py
    3.5.2 (default, Nov 12 2018, 13:43:14)
    [GCC 5.4.0 20160609] on linux
    
    ['root_dir', ['dir2', 'dir1', 'dir3', 'dir0'], ['file1', 'file0']]


  1. [ActiveState.Docs]: win32file.FindFilesW ( spécifique à Win )

    Récupère une liste de noms de fichiers correspondants à l'aide de l'API Windows Unicode. Une interface vers les fonctions de fermeture de l'API FindFirstFileW / FindNextFileW / Find.


    >>> import os, win32file, win32con
    >>> root_dir = "root_dir"
    >>> wildcard = "*"
    >>> root_dir_wildcard = os.path.join(root_dir, wildcard)
    >>> entry_list = win32file.FindFilesW(root_dir_wildcard)
    >>> len(entry_list)  # Don't display the whole content as it's too long
    8
    >>> [entry[-2] for entry in entry_list]  # Only display the entry names
    ['.', '..', 'dir0', 'dir1', 'dir2', 'dir3', 'file0', 'file1']
    >>>
    >>> [entry[-2] for entry in entry_list if entry[0] & win32con.FILE_ATTRIBUTE_DIRECTORY and entry[-2] not in (".", "..")]  # Filter entries and only display dir names (except self and parent)
    ['dir0', 'dir1', 'dir2', 'dir3']
    >>>
    >>> [os.path.join(root_dir, entry[-2]) for entry in entry_list if entry[0] & (win32con.FILE_ATTRIBUTE_NORMAL | win32con.FILE_ATTRIBUTE_ARCHIVE)]  # Only display file "full" names
    ['root_dir\\file0', 'root_dir\\file1']

    Remarques :


  1. Installez un (autre) paquet tiers qui fait l'affaire
    • Très probablement, s'appuiera sur l'un (ou plusieurs) des éléments ci-dessus (peut-être avec de légères personnalisations)


Remarques :

  • Le code est censé être portable (sauf les endroits qui ciblent une zone spécifique - qui sont marqués) ou croisés:

    • Plate-forme ( Nix , Win ,)
    • Version Python (2, 3,)
  • Plusieurs styles de chemin (absolu, apparenté) ont été utilisés dans les variantes ci-dessus, pour illustrer le fait que les "outils" utilisés sont flexibles dans cette direction.

  • os.listdiret os.scandirutilisez opendir / readdir / closedir ( [MS.Docs]: fonction FindFirstFileW / [MS.Docs]: fonction FindNextFileW / [MS.Docs]: fonction FindClose ) (via [GitHub]: python / cpython - (master) cpython / Modules / posixmodule.c )

  • win32file.FindFilesWutilise également ces fonctions ( spécifiques à Win ) (via [GitHub]: mhammond / pywin32 - (master) pywin32 / win32 / src / win32file.i )

  • _get_dir_content (à partir du point # 1. ) peut être implémenté en utilisant n'importe laquelle de ces approches (certaines nécessiteront plus de travail et d'autres moins)

    • Un filtrage avancé (au lieu de simplement fichier vs dir) pourrait être fait: par exemple, l' argument include_folders pourrait être remplacé par un autre (par exemple filter_func ) qui serait une fonction qui prend un chemin en argument:filter_func=lambda x: True (cela ne supprime pas n'importe quoi) et à l'intérieur de _get_dir_content quelque chose comme: if not filter_func(entry_with_path): continue(si la fonction échoue pour une entrée, elle sera ignorée), mais plus le code devient complexe, plus il faudra de temps pour l'exécuter
  • Nota bene! Puisque la récursivité est utilisée, je dois mentionner que j'ai fait des tests sur mon ordinateur portable ( Win 10 x64 ), totalement sans rapport avec ce problème, et lorsque le niveau de récursivité atteignait des valeurs quelque part dans la plage ( 990 .. 1000) ( recursionlimit - 1000 (par défaut)), j'ai obtenu StackOverflow :). Si l'arborescence de répertoires dépasse cette limite (je ne suis pas un expert FS , donc je ne sais pas si c'est même possible), cela pourrait être un problème.
    Je dois également mentionner que je n'ai pas essayé d'augmenter la limite de récursivité car je n'ai aucune expérience dans le domaine (combien puis-je l'augmenter avant d'avoir à augmenter également la pile à OSniveau), mais en théorie, il y aura toujours la possibilité d'échec, si la profondeur dir est supérieure à la limite de récursivité la plus élevée possible (sur cette machine)

  • Les exemples de code sont uniquement à des fins de démonstration. Cela signifie que je n'ai pas pris en compte la gestion des erreurs (je ne pense pas qu'il y ait de bloc try / except / else / finally ), donc le code n'est pas robuste (la raison est: pour le garder aussi simple et court que possible ). Pour la production , la gestion des erreurs doit également être ajoutée

Autres approches:

  1. Utiliser Python uniquement comme wrapper

    • Tout se fait en utilisant une autre technologie
    • Cette technologie est invoquée depuis Python
    • La saveur la plus célèbre que je connaisse est ce que j'appelle l' approche de l' administrateur système :

      • Utilisez Python (ou n'importe quel langage de programmation d'ailleurs) pour exécuter des commandes shell (et analyser leurs sorties)
      • Certains considèrent cela comme un hack soigné
      • Je le considère plus comme une solution de contournement boiteuse ( gainarie ), car l'action en soi est effectuée à partir du shell ( cmd dans ce cas), et n'a donc rien à voir avec Python .
      • Le filtrage ( grep/ findstr) ou le formatage de sortie pourrait être fait des deux côtés, mais je ne vais pas insister là-dessus. Aussi, j'ai délibérément utilisé os.systemau lieu de subprocess.Popen.
      (py35x64_test) E:\Work\Dev\StackOverflow\q003207219>"e:\Work\Dev\VEnvs\py35x64_test\Scripts\python.exe" -c "import os;os.system(\"dir /b root_dir\")"
      dir0
      dir1
      dir2
      dir3
      file0
      file1

    En général, cette approche est à éviter, car si certains formats de sortie de commande diffèrent légèrement entre les versions / versions du système d'exploitation , le code d'analyse doit également être adapté; sans parler des différences entre les paramètres régionaux).

CristiFati
la source
48

J'ai vraiment aimé la réponse d'Adamk , suggérant que vous l' utilisiezglob() , à partir du module du même nom. Cela vous permet d'avoir une correspondance de motifs avec *s.

Mais comme d'autres personnes l'ont souligné dans les commentaires, glob()peuvent se tromper en raison de directions incohérentes. Pour vous aider, je vous suggère d'utiliser lejoin()expanduser() fonctions et dans le os.pathmodule, et peut-être legetcwd() fonction dans leos module.

À titre d'exemples:

from glob import glob

# Return everything under C:\Users\admin that contains a folder called wlp.
glob('C:\Users\admin\*\wlp')

Ce qui précède est terrible - le chemin a été codé en dur et ne fonctionnera que sur Windows entre le nom du lecteur et le \ s en dur dans le chemin.

from glob    import glob
from os.path import join

# Return everything under Users, admin, that contains a folder called wlp.
glob(join('Users', 'admin', '*', 'wlp'))

Ce qui précède fonctionne mieux, mais il repose sur le nom du dossier Usersqui se trouve souvent sur Windows et pas si souvent sur d'autres systèmes d'exploitation. Il repose également sur l'utilisateur ayant un nom spécifique,admin .

from glob    import glob
from os.path import expanduser, join

# Return everything under the user directory that contains a folder called wlp.
glob(join(expanduser('~'), '*', 'wlp'))

Cela fonctionne parfaitement sur toutes les plateformes.

Un autre excellent exemple qui fonctionne parfaitement sur toutes les plateformes et fait quelque chose d'un peu différent:

from glob    import glob
from os      import getcwd
from os.path import join

# Return everything under the current directory that contains a folder called wlp.
glob(join(getcwd(), '*', 'wlp'))

J'espère que ces exemples vous aideront à voir la puissance de quelques-unes des fonctions que vous pouvez trouver dans les modules de bibliothèque Python standard.

ArtOfWarfare
la source
4
Extra fun: à partir de Python 3.5, **fonctionne aussi longtemps que vous le définissez recursive = True. Voir les documents ici: docs.python.org/3.5/library/glob.html#glob.glob
ArtOfWarfare
36
def list_files(path):
    # returns a list of names (with extension, without full path) of all files 
    # in folder path
    files = []
    for name in os.listdir(path):
        if os.path.isfile(os.path.join(path, name)):
            files.append(name)
    return files 
Apogentus
la source
Merci! travaux! parfait!
ambigus9
23

Si vous recherchez une implémentation Python de find , voici une recette que j'utilise assez fréquemment:

from findtools.find_files import (find_files, Match)

# Recursively find all *.sh files in **/usr/bin**
sh_files_pattern = Match(filetype='f', name='*.sh')
found_files = find_files(path='/usr/bin', match=sh_files_pattern)

for found_file in found_files:
    print found_file

J'en ai donc fait un paquet PyPI et il y a aussi un dépôt GitHub . J'espère que quelqu'un le trouve potentiellement utile pour ce code.

Yauhen Yakimovich
la source
14

Pour de meilleurs résultats, vous pouvez utiliser la listdir()méthodeos module avec un générateur (un générateur est un itérateur puissant qui garde son état, vous vous souvenez?). Le code suivant fonctionne correctement avec les deux versions: Python 2 et Python 3.

Voici un code:

import os

def files(path):  
    for file in os.listdir(path):
        if os.path.isfile(os.path.join(path, file)):
            yield file

for file in files("."):  
    print (file)

La listdir()méthode renvoie la liste des entrées pour le répertoire donné. La méthode os.path.isfile()retourne Truesi l'entrée donnée est un fichier. L' yieldopérateur quitte la fonction mais conserve son état actuel et ne renvoie que le nom de l'entrée détectée sous forme de fichier. Tout ce qui précède nous permet de boucler sur la fonction du générateur.

Andy
la source
11

Renvoyer une liste de chemins de fichiers absolus, n'est pas récurrent dans les sous-répertoires

L = [os.path.join(os.getcwd(),f) for f in os.listdir('.') if os.path.isfile(os.path.join(os.getcwd(),f))]
The2ndSon
la source
2
Remarque: os.path.abspath(f)serait un substitut un peu moins cher os.path.join(os.getcwd(),f).
ShadowRanger
Je serais encore plus efficace si vous commenciez par cwd = os.path.abspath('.'), puis utilisé à la cwdplace de '.'et os.getcwd()tout au long pour éviter des charges d'appels système redondants.
Martijn Pieters
10
import os
import os.path


def get_files(target_dir):
    item_list = os.listdir(target_dir)

    file_list = list()
    for item in item_list:
        item_dir = os.path.join(target_dir,item)
        if os.path.isdir(item_dir):
            file_list += get_files(item_dir)
        else:
            file_list.append(item_dir)
    return file_list

Ici, j'utilise une structure récursive.

pah8J
la source
La même chose peut être réalisée en une seule ligne avec pathlib:filter(Path.is_file, Path().rglob('*'))
Georgy
9

Un sage enseignant m'a dit une fois que:

Lorsqu'il existe plusieurs façons établies de faire quelque chose, aucune n'est bonne pour tous les cas.

J'ajouterai donc une solution pour un sous - ensemble du problème: bien souvent, nous voulons seulement vérifier si un fichier correspond à une chaîne de début et une chaîne de fin, sans entrer dans les sous-répertoires. Nous aimerions donc une fonction qui retourne une liste de noms de fichiers, comme:

filenames = dir_filter('foo/baz', radical='radical', extension='.txt')

Si vous souhaitez d'abord déclarer deux fonctions, cela peut être fait:

def file_filter(filename, radical='', extension=''):
    "Check if a filename matches a radical and extension"
    if not filename:
        return False
    filename = filename.strip()
    return(filename.startswith(radical) and filename.endswith(extension))

def dir_filter(dirname='', radical='', extension=''):
    "Filter filenames in directory according to radical and extension"
    if not dirname:
        dirname = '.'
    return [filename for filename in os.listdir(dirname)
                if file_filter(filename, radical, extension)]

Cette solution pourrait être facilement généralisée avec des expressions régulières (et vous voudrez peut-être ajouter un patternargument, si vous ne voulez pas que vos modèles restent toujours au début ou à la fin du nom de fichier).

fralau
la source
6

Utilisation de générateurs

import os
def get_files(search_path):
     for (dirpath, _, filenames) in os.walk(search_path):
         for filename in filenames:
             yield os.path.join(dirpath, filename)
list_files = get_files('.')
for filename in list_files:
    print(filename)
shantanoo
la source
4

Une autre variante très lisible pour Python 3.4+ utilise pathlib.Path.glob:

from pathlib import Path
folder = '/foo'
[f for f in Path(folder).glob('*') if f.is_file()]

Il est simple de le rendre plus spécifique, par exemple, ne recherchez que les fichiers source Python qui ne sont pas des liens symboliques, également dans tous les sous-répertoires:

[f for f in Path(folder).glob('**/*.py') if not f.is_symlink()]
fhchl
la source
3

Voici ma fonction polyvalente pour cela. Il retourne une liste de chemins de fichiers plutôt que des noms de fichiers car j'ai trouvé que c'était plus utile. Il a quelques arguments facultatifs qui le rendent polyvalent. Par exemple, je l'utilise souvent avec des arguments comme pattern='*.txt'ou subfolders=True.

import os
import fnmatch

def list_paths(folder='.', pattern='*', case_sensitive=False, subfolders=False):
    """Return a list of the file paths matching the pattern in the specified 
    folder, optionally including files inside subfolders.
    """
    match = fnmatch.fnmatchcase if case_sensitive else fnmatch.fnmatch
    walked = os.walk(folder) if subfolders else [next(os.walk(folder))]
    return [os.path.join(root, f)
            for root, dirnames, filenames in walked
            for f in filenames if match(f, pattern)]
MarredCheese
la source
2

Je vais fournir un exemple d'un liner où le chemin source et le type de fichier peuvent être fournis en entrée. Le code renvoie une liste de noms de fichiers avec l'extension csv. Utilisez . au cas où tous les fichiers doivent être retournés. Cela balaye également récursivement les sous-répertoires.

[y for x in os.walk(sourcePath) for y in glob(os.path.join(x[0], '*.csv'))]

Modifiez les extensions de fichier et le chemin source selon vos besoins.

Vinodh Krishnaraju
la source
1
Si vous allez utiliser glob, utilisez simplement glob('**/*.csv', recursive=True). Pas besoin de combiner cela avec os.walk()pour recurse ( recursiveet **sont pris en charge depuis Python 3.5).
Martijn Pieters
2

Pour python2: pip install rglob

import rglob
file_list=rglob.rglob("/home/base/dir/", "*")
print file_list
chris-piekarski
la source
2

dircache est "obsolète depuis la version 2.6: le module dircache a été supprimé dans Python 3.0."

import dircache
list = dircache.listdir(pathname)
i = 0
check = len(list[0])
temp = []
count = len(list)
while count != 0:
  if len(list[i]) != check:
     temp.append(list[i-1])
     check = len(list[i])
  else:
    i = i + 1
    count = count - 1

print temp
shaji
la source
17
dirchache est "obsolète depuis la version 2.6: le module dircache a été supprimé dans Python 3.0."
Daniel Reis