Come elenco tutti i file di una directory?


Risposte:


4216

os.listdir()ti porterà tutto ciò che è in una directory: file e directory .

Se vuoi solo i file, puoi filtrarlo usando os.path:

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

o potresti usare quello os.walk()che produrrà due elenchi per ogni directory che visita - suddividendo in file e directory per te. Se vuoi solo la directory principale puoi semplicemente rompere la prima volta che produce

from os import walk

f = []
for (dirpath, dirnames, filenames) in walk(mypath):
    f.extend(filenames)
    break

87
Un po 'più semplice: (_, _, filenames) = walk(mypath).next() (se sei sicuro che la camminata restituirà almeno un valore, che dovrebbe.)
misterbee,

9
Leggera modifica per memorizzare percorsi completi: per (dirpath, dirnames, nomi file) in os.walk (mypath): checksum_files.extend (os.path.join (dirpath, nome file) per nome file nei nomi file) break
okigan

150
f.extend(filenames)non è effettivamente equivalente a f = f + filenames. extendverrà modificato fsul posto, mentre l'aggiunta crea un nuovo elenco in una nuova posizione di memoria. Questo significa che extendè generalmente più efficiente di +, ma a volte può creare confusione se più oggetti contengono riferimenti all'elenco. Infine, vale la pena notare che f += filenamesequivale a f.extend(filenames), non è f = f + filenames .
Benjamin Hodgson

30
@misterbee, la tua soluzione è la migliore, solo un piccolo miglioramento:_, _, filenames = next(walk(mypath), (None, None, []))
bgusach

35
in python 3.x usare(_, _, filenames) = next(os.walk(mypath))
ET-CS il

1684

Preferisco usare il globmodulo, in quanto fa adattamento ed espansione del modello.

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

Restituirà un elenco con i file interrogati:

['/home/adam/file1.txt', '/home/adam/file2.txt', .... ]

17
questa è una scorciatoia per listdir + fnmatch docs.python.org/library/fnmatch.html#fnmatch.fnmatch
Stefano

31
per chiarire, ciò non restituisce il "percorso completo"; restituisce semplicemente l'espansione del glob, qualunque esso sia. Ad esempio, dato /home/user/foo/bar/hello.txt, quindi, se in esecuzione nella directory foo, glob("bar/*.txt")verrà restituito bar/hello.txt. Ci sono casi in cui in realtà vuoi il percorso completo (cioè assoluto); per questi casi, consultare stackoverflow.com/questions/51520/…
michael

1
Correlati: trova i file in modo ricorsivo con glob: stackoverflow.com/a/2186565/4561887
Gabriel Staples

6
non risponde a questa domanda. glob.glob("*")voluto.
Jean-François Fabre

bellissimo!!!! quindi .... x=glob.glob("../train/*.png")mi darà una serie di percorsi, purché conosca il nome della cartella. Così bello!
Jennifer Crosby il

860

Ottieni un elenco di file con Python 2 e 3


os.listdir()

Come ottenere tutti i file (e le directory) nella directory corrente (Python 3)

Di seguito, sono semplici metodi per recuperare solo i file nella directory corrente, usando os e la listdir()funzione, in Python 3. Ulteriori esplorazioni, dimostreranno come restituire le cartelle nella directory, ma non si avrà il file nella sottodirectory, per quello che può usare walk - discusso più avanti).

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

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

glob

Ho trovato glob più facile selezionare il file dello stesso tipo o con qualcosa in comune. Guarda il seguente esempio:

import glob

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

glob con comprensione dell'elenco

import glob

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

glob con una funzione

La funzione restituisce un elenco dell'estensione fornita (.txt, .docx ecc.) Nell'argomento

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 l'estensione del codice precedente

La funzione ora restituisce un elenco di file che corrisponde alla stringa che si passa come argomento

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)}")

produzione

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

Ottenere il nome completo del percorso con os.path.abspath

Come hai notato, non hai il percorso completo del file nel codice sopra. Se devi avere il percorso assoluto, puoi usare un'altra funzione del os.pathmodulo chiamata _getfullpathname, mettendo il file che ottieni os.listdir()come argomento. Esistono altri modi per avere il percorso completo, come controlleremo più avanti (ho sostituito, come suggerito da mexmex, _getfullpathname con 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']

Ottieni il nome percorso completo di un tipo di file in tutte le sottodirectory con walk

Lo trovo molto utile per trovare cose in molte directory e mi ha aiutato a trovare un file sul quale non ricordavo il nome:

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(): recupera i file nella directory corrente (Python 2)

In Python 2, se si desidera l'elenco dei file nella directory corrente, è necessario fornire l'argomento come '.' o os.getcwd () nel metodo os.listdir.

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

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

Per salire nella struttura delle directory

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

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

Ottieni file: os.listdir()in una directory particolare (Python 2 e 3)

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

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

Ottieni file di una sottodirectory particolare con os.listdir()

import os

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

os.walk('.') - directory corrente

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

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

next(os.walk('.')) e 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:\\') - ottenere il percorso completo - comprensione della lista

 [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 - ottieni il percorso completo - tutti i file nelle directory secondarie **

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() - Ottieni solo file txt

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

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

Utilizzo globper ottenere il percorso completo dei file

Se dovessi aver bisogno del percorso assoluto dei file:

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

Utilizzo os.path.isfileper evitare directory nell'elenco

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

Utilizzo pathlibda 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

Con list comprehension:

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

In alternativa, utilizzare pathlib.Path()invece dipathlib.Path(".")

Usa il metodo glob in pathlib.Path ()

import pathlib

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

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

Ottieni tutti e solo i file con 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']

Ottieni solo i file con next e cammina in una directory

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

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

Ottieni solo le directory con next e cammina in una directory

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

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

Ottieni tutti i nomi dei subdir con 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() da Python 3.5 e versioni successive

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

Esempi:

Ex. 1: quanti file ci sono nelle sottodirectory?

In questo esempio, cerchiamo il numero di file inclusi in tutte le directory e nelle sue sottodirectory.

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: Come copiare tutti i file da una directory a un'altra?

Uno script per effettuare l'ordine nel tuo computer che trova tutti i file di un tipo (impostazione predefinita: pptx) e li copia in una nuova cartella.

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: Come ottenere tutti i file in un file txt

Nel caso in cui si desideri creare un file txt con tutti i nomi di file:

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

Esempio: txt con tutti i file di un disco rigido

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

Tutto il file di C: \ in un file di testo

Questa è una versione più breve del codice precedente. Cambia la cartella da cui iniziare a trovare i file se devi iniziare da un'altra posizione. Questo codice genera un file di testo di 50 mb sul mio computer con qualcosa in meno di 500.000 righe con file con il percorso completo.

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

Come scrivere un file con tutti i percorsi in una cartella di un tipo

Con questa funzione puoi creare un file txt che avrà il nome di un tipo di file che cerchi (es. Pngfile.txt) con tutto il percorso completo di tutti i file di quel tipo. A volte può essere utile, penso.

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

(Novità) Trova tutti i file e aprili con la GUI di tkinter

Volevo solo aggiungere in questo 2019 una piccola app per cercare tutti i file in una directory ed essere in grado di aprirli facendo doppio clic sul nome del file nell'elenco. inserisci qui la descrizione dell'immagine

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

14
Questo è un miscuglio di troppe risposte a domande non poste qui. Potrebbe anche valere la pena spiegare quali sono le avvertenze o gli approcci raccomandati. Non sto meglio conoscendo un modo contro 20 modi di fare la stessa cosa a meno che non sappia anche quale è più appropriato usare quando.
cs95,

Ok, al più presto darò un'occhiata alla mia risposta e cercherò di renderla più pulita e con informazioni più utili sulla differenza tra i metodi ecc.
Giovanni G. PY

Non è necessario determinare l'estensione del file controllando se il nome file contiene una sottostringa. Ciò potrebbe causare molti problemi. Consiglio di verificare sempre se il nome file termina con la sottostringa particolare.
Ni1ight

Ok, @ n1light ho cambiato il codice ...
Giovanni G. PY il

812
import os
os.listdir("somedirectory")

restituirà un elenco di tutti i file e le directory in "somedirectory".


11
Questo restituisce il percorso relativo dei file, rispetto al percorso completo restituito daglob.glob
xji

22
@JIXiang: os.listdir()restituisce sempre semplici nomi di file (non percorsi relativi). Ciò che glob.glob()ritorna è guidato dal formato del percorso del modello di input.
mklement0

os.listdir () -> Elenca sempre la directory e il file all'interno della posizione fornita. Esiste un modo per elencare solo directory e non file?
RonyA

160

Una soluzione su una riga per ottenere solo un elenco di file (nessuna sottodirectory):

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

o nomi di percorso assoluti:

paths = [os.path.join(path, fn) for fn in next(os.walk(path))[2]]

7
Solo una riga se hai già import os. Sembra meno conciso che glob()a me.
ArtOfWarfare,

4
il problema con glob è che una cartella chiamata "qualcosa. qualcosa" verrebbe restituita da glob ("/ home / adam /*.*")
Remi

6
Su OS X, c'è qualcosa chiamato un bundle. È una directory che generalmente dovrebbe essere trattata come un file (come un .tar). Vorresti quelli trattati come un file o una directory? L'uso glob()lo tratterebbe come un file. Il tuo metodo lo tratterà come una directory.
ArtOfWarfare

132

Ottenere percorsi di file completi da una directory e da tutte le sue sottodirectory

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

  • Il percorso che ho fornito nella funzione precedente conteneva 3 file: due nella directory principale e un altro in una sottocartella denominata "SUBFOLDER". Ora puoi fare cose come:
  • print full_file_paths che stamperà l'elenco:

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

Se lo desideri, puoi aprire e leggere i contenuti o concentrarti solo sui file con estensione ".dat" come nel codice seguente:

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

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


Questa è l'unica e sola risposta.
studente

78

Dalla versione 3.4 ci sono iteratori integrati per questo che sono molto più efficienti di os.listdir():

pathlib: Nuovo nella versione 3.4.

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

Secondo PEP 428 , lo scopo della pathliblibreria è fornire una semplice gerarchia di classi per gestire i percorsi del filesystem e le operazioni comuni che gli utenti eseguono su di essi.

os.scandir(): Nuovo nella versione 3.5.

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

Si noti che os.walk()utilizza os.scandir()invece che os.listdir()dalla versione 3.5 e la sua velocità è stata aumentata di 2-20 volte secondo PEP 471 .

Vorrei anche raccomandare di leggere il commento di ShadowRanger qui sotto.


1
Grazie! Penso che sia l'unica soluzione a non restituire direttamente a list. Potrebbe usare al p.nameposto del primo in palternativa, se preferito.
Jeromej,

1
Benvenuto! Preferirei generare pathlib.Path()istanze poiché hanno molti metodi utili che non vorrei sprecare. Puoi anche chiamarli str(p)per i nomi dei percorsi.
SzieberthAdam,

6
Nota: la os.scandirsoluzione sarà più efficiente che os.listdircon un os.path.is_filecontrollo o simili, anche se hai bisogno di un list(quindi non trarrai vantaggio dall'iterazione lenta), perché os.scandirutilizza le API fornite dal sistema operativo che ti forniscono le is_fileinformazioni gratuitamente mentre scorre , non per file di andata e ritorno al disco per statloro a tutti (su Windows, le DirEntrys farti completa statinformazioni per libero, su sistemi * nix ha bisogno di statper informazioni al di là is_file, is_dire così via, ma DirEntrycache sul primo statper comodità).
ShadowRanger,

1
È inoltre possibile utilizzare entry.nameper ottenere solo il nome del file o entry.pathper ottenere il suo percorso completo. Non più os.path.join () dappertutto.
user136036

56

Note preliminari

  • Sebbene ci sia una chiara differenziazione tra termini di file e directory nel testo della domanda, alcuni potrebbero obiettare che le directory sono in realtà file speciali
  • L'istruzione: " tutti i file di una directory " possono essere interpretati in due modi:
    1. Tutte le dirette (o livello 1) discendenti solo
    2. Tutti i discendenti nell'intero albero di directory (inclusi quelli nelle sottodirectory)
  • Quando è stata posta la domanda, immagino che Python 2 fosse la versione LTS , tuttavia gli esempi di codice verranno eseguiti da Python 3 ( .5 ) (li terrò il più possibile compatibili con Python 2 ; inoltre, qualsiasi codice appartenente a Python che ho intenzione di pubblicare è dalla v3.5.4 - se non diversamente specificato). Ciò ha conseguenze relative a un'altra parola chiave nella domanda: " aggiungili a un elenco ":

    • Nelle versioni pre Python 2.2 , le sequenze (iterabili) erano per lo più rappresentate da elenchi (tuple, set, ...)
    • In Python 2.2 è stato introdotto il concetto di generatore ( [Python.Wiki]: Generatori ) - per gentile concessione di [Python 3]: la dichiarazione di rendimento ). Col passare del tempo, le controparti del generatore hanno iniziato a comparire per le funzioni che hanno restituito / lavorato con gli elenchi
    • In Python 3 , generatore è il comportamento predefinito
    • Non sono sicuro se la restituzione di un elenco sia ancora obbligatoria (o lo farebbe anche un generatore), ma passare un generatore al costruttore dell'elenco , ne creerà un elenco (e lo consumerà). L'esempio seguente illustra le differenze su [Python 3]: map ( funzione, iterabile, ... )
    >>> 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'>)
  • Gli esempi saranno basati su una directory chiamata root_dir con la seguente struttura (questo esempio è per Win , ma sto usando lo stesso albero anche su 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


soluzioni

Approcci programmatici:

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

    Restituisce un elenco contenente i nomi delle voci nella directory fornite dal percorso. L'elenco è in ordine arbitrario e non include le voci speciali '.'e '..'...


    >>> 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 esempio più elaborato ( 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()

    Note :

    • Esistono due implementazioni:
      • Uno che utilizza generatori (ovviamente qui sembra inutile, poiché converto immediatamente il risultato in un elenco)
      • Quello classico (nomi delle funzioni che terminano con _old )
    • Viene utilizzata la ricorsione (per accedere alle sottodirectory)
    • Per ogni implementazione ci sono due funzioni:
      • Uno che inizia con un carattere di sottolineatura ( _ ): "privato" (non dovrebbe essere chiamato direttamente) - che fa tutto il lavoro
      • Quello pubblico (wrapper rispetto al precedente): rimuove semplicemente il percorso iniziale (se richiesto) dalle voci restituite. È una brutta implementazione, ma è l'unica idea che potrei venire a questo punto
    • In termini di prestazioni, i generatori sono generalmente un po 'più veloci (considerando sia i tempi di creazione che quelli di iterazione ), ma non li ho testati in funzioni ricorsive e sto anche iterando all'interno della funzione rispetto ai generatori interni - non so come le prestazioni è amichevole
    • Gioca con gli argomenti per ottenere risultati diversi


    Uscita :

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

    Restituisce un iteratore di oggetti os.DirEntry corrispondenti alle voci nella directory fornite dal percorso . Le voci sono rese in ordine arbitrario e le voci speciali '.'e '..'non sono incluse.

    L'uso di scandir () anziché listdir () può aumentare significativamente le prestazioni del codice che necessita anche di informazioni sul tipo di file o sugli attributi di file, poiché gli oggetti os.DirEntry espongono queste informazioni se il sistema operativo le fornisce durante la scansione di una directory. Tutti i metodi os.DirEntry possono eseguire una chiamata di sistema, ma is_dir () e is_file () di solito richiedono solo una chiamata di sistema per collegamenti simbolici; os.DirEntry.stat () richiede sempre una chiamata di sistema su Unix ma ne richiede solo una per i collegamenti simbolici su 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

    Note :

    • È simile a os.listdir
    • Ma è anche più flessibile (e offre più funzionalità), più Python ic (e in alcuni casi, più veloce)


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

    Generare i nomi dei file in un albero di directory percorrendo l'albero dall'alto verso il basso o dal basso verso l'alto. Per ogni directory nella struttura di radice in directory superiore (compresa la parte superiore stessa), produce un 3-tupla ( 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', [], [])

    Note :

    • Sotto le scene, utilizza os.scandir( os.listdirnelle versioni precedenti)
    • Fa il sollevamento pesante ricorrendo in sottocartelle


  1. [Python 3]: glob. glob ( nome percorso, *, ricorsivo = falso ) ( [Python 3]: glob. iglob ( percorso, *, ricorsivo = falso ) )

    Restituisce un elenco possibilmente vuoto di nomi di percorso che corrispondono a nome percorso , che deve essere una stringa contenente una specifica del percorso. il percorso può essere assoluto (simile /usr/src/Python-1.5/Makefile) o relativo (simile ../../Tools/*/*.gif) e può contenere caratteri jolly in stile shell. I link simbolici non funzionanti sono inclusi nei risultati (come nella shell).
    ...
    Modificato nella versione 3.5 : Supporto per globi ricorsivi utilizzando " **".


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

    Note :

    • usi os.listdir
    • Per alberi di grandi dimensioni (specialmente se è attivo il ricorsivo ), si preferisce iglob
    • Consente filtri avanzati in base al nome (a causa del carattere jolly)


  1. [Python 3]: pathlib di classe. Path ( * pathegments ) ( 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']

    Note :

    • Questo è un modo per raggiungere il nostro obiettivo
    • È lo stile OOP dei percorsi di gestione
    • Offre molte funzionalità


  1. [Python 2]: dircache.listdir (percorso) ( solo Python 2 )


    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) tramite [Python 3]: ctypes - Una libreria di funzioni esterne per Python ( specifica POSIX )

    ctypes è una libreria di funzioni estranee per Python. Fornisce tipi di dati compatibili con C e consente di chiamare funzioni in DLL o librerie condivise. Può essere usato per avvolgere queste librerie in Python puro.

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

    Note :

    • Carica le tre funzioni da libc (caricate nel processo corrente) e le chiama (per maggiori dettagli controlla [SO]: Come posso verificare se un file esiste senza eccezioni? (Risposta di @ CristiFati) - ultime note dal punto 4. ). Ciò porterebbe questo approccio molto vicino al limite Python / C
    • LinuxDirent64 è la rappresentazione dei tipi di struct dirent64 da [ man7 ]: dirent.h (0P) (così sono le costanti DT_ ) dalla mia macchina: Ubtu 16 x64 ( 4.10.0-40-generic e libc6-dev: amd64 ). Su altri sapori / versioni, la definizione struct potrebbe differire, e in caso affermativo, le ctypes alias devono essere aggiornati, altrimenti si produrrà un comportamento indefinito
    • Restituisce i dati nel os.walkformato di. Non mi sono preoccupato di renderlo ricorsivo, ma a partire dal codice esistente, sarebbe stato un compito abbastanza banale
    • Tutto è fattibile anche su Win , i dati (librerie, funzioni, strutture, costanti, ...) differiscono


    Uscita :

    [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 ( specifico per Win )

    Recupera un elenco di nomi file corrispondenti, utilizzando l'API Unicode di Windows. Un'interfaccia all'API FindFirstFileW / FindNextFileW / Trova chiudi le funzioni.


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

    Note :


  1. Installa alcuni (altri) pacchetti di terze parti che risolvono il problema
    • Molto probabilmente, si baserà su uno (o più) di quanto sopra (forse con lievi personalizzazioni)


Note :

  • Il codice è pensato per essere portatile (tranne i luoghi che hanno come target un'area specifica - che sono contrassegnati) o incrociati:

    • piattaforma ( Nix , Win ,)
    • Versione Python (2, 3,)
  • Stili di percorso multipli (assoluti, relativi) sono stati utilizzati tra le varianti sopra, per illustrare il fatto che gli "strumenti" utilizzati sono flessibili in questa direzione

  • os.listdire os.scandirusa opendir / readdir / closedir ( [MS.Docs]: funzione FindFirstFileW / [MS.Docs]: funzione FindNextFileW / [MS.Docs]: funzione FindClose ) (tramite [GitHub]: python / cpython - (master) cpython / Moduli / posixmodule.c )

  • win32file.FindFilesWusa anche quelle funzioni ( specifiche di Win ) (tramite [GitHub]: mhammond / pywin32 - (master) pywin32 / win32 / src / win32file.i )

  • _get_dir_content (dal punto 1 ) può essere implementato utilizzando uno di questi approcci (alcuni richiederanno più lavoro e altri meno)

    • Potrebbero essere eseguiti alcuni filtri avanzati (anziché solo file vs. dir): ad esempio l' argomento include_folders potrebbe essere sostituito da un altro (ad esempio filter_func ) che sarebbe una funzione che prende un percorso come argomento: filter_func=lambda x: True(questo non rimuove qualcosa) e dentro _get_dir_content qualcosa del tipo: if not filter_func(entry_with_path): continue(se la funzione fallisce per una voce, verrà saltata), ma più il codice diventa complesso, più tempo ci vorrà per eseguire
  • Nota bene! Da quando viene utilizzata la ricorsione, devo dire che ho fatto alcuni test sul mio laptop ( Win 10 x64 ), totalmente estraneo a questo problema, e quando il livello di ricorsione raggiungeva valori da qualche parte nell'intervallo (990 .. 1000) ( recursionlimit - 1000 (impostazione predefinita)), ho StackOverflow :). Se l'albero delle directory supera quel limite (non sono un esperto di FS , quindi non so se sia possibile), potrebbe essere un problema.
    Devo anche menzionare che non ho provato ad aumentare il limite di ricorsione perché non ho esperienza nell'area (quanto posso aumentarlo prima di dover aumentare anche lo stack sul sistema operativolivello), ma in teoria ci sarà sempre la possibilità di fallimento, se la profondità dir è maggiore del limite di ricorsione più alto possibile (su quella macchina)

  • Gli esempi di codice sono solo a scopo dimostrativo. Ciò significa che non ho preso in considerazione la gestione degli errori (non credo che ci sia alcun tentativo / tranne / else / finally block), quindi il codice non è robusto (il motivo è: mantenerlo il più semplice e breve possibile ). Per la produzione , è necessario aggiungere anche la gestione degli errori

Altri approcci:

  1. Usa Python solo come wrapper

    • Tutto viene fatto usando un'altra tecnologia
    • Quella tecnologia è invocata da Python
    • Il sapore più famoso che conosco è quello che chiamo l' approccio dell'amministratore di sistema :

      • Usa Python (o qualsiasi linguaggio di programmazione per quella materia) per eseguire i comandi della shell (e analizzare i loro output)
      • Alcuni lo considerano un trucco ordinato
      • Lo considero più come una soluzione scadente ( gainarie ), poiché l'azione di per sé viene eseguita dalla shell ( cmd in questo caso), e quindi non ha nulla a che fare con Python .
      • Il filtro ( grep/ findstr) o la formattazione dell'output potrebbero essere eseguiti su entrambi i lati, ma non ho intenzione di insistere. Inoltre, ho usato deliberatamente os.systeminvece di 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

    In generale questo approccio deve essere evitato, poiché se un formato di output del comando differisce leggermente tra versioni / sapori del sistema operativo , anche il codice di analisi dovrebbe essere adattato; per non parlare delle differenze tra i locali).


48

Mi è davvero piaciuta la risposta di Adamk , suggerendoti di usare glob(), dal modulo con lo stesso nome. Questo ti permette di avere un pattern matching con *s.

Ma come altre persone hanno sottolineato nei commenti, glob()possono inciampare in direzioni incoerenti. Per aiutarti, ti suggerisco di usare le funzioni join()e expanduser()nel os.pathmodulo, e forse anche la getcwd()funzione nel osmodulo.

Come esempi:

from glob import glob

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

Quanto sopra è terribile - il percorso è stato hardcoded e funzionerà sempre e solo su Windows tra il nome dell'unità e il \codice hardcoded nel percorso.

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

Quanto sopra funziona meglio, ma si basa sul nome della cartella Usersche si trova spesso su Windows e non così spesso trovato su altri sistemi operativi. Essa si basa anche su l'utente avere un nome specifico, 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'))

Funziona perfettamente su tutte le piattaforme.

Un altro ottimo esempio che funziona perfettamente su tutte le piattaforme e fa qualcosa di leggermente diverso:

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

Spero che questi esempi ti aiutino a vedere la potenza di alcune delle funzioni che puoi trovare nei moduli della libreria Python standard.


4
Divertimento extra: a partire da Python 3.5, **funziona tutto il tempo impostato recursive = True. Vedi i documenti qui: docs.python.org/3.5/library/glob.html#glob.glob
ArtOfWarfare il

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 

Grazie! lavori! Perfetto!
ambigus9

23

Se stai cercando un'implementazione di Python di find , questa è una ricetta che uso piuttosto frequentemente:

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

Quindi ne ho ricavato un pacchetto PyPI e c'è anche un repository GitHub . Spero che qualcuno lo trovi potenzialmente utile per questo codice.


14

Per risultati migliori, puoi usare il listdir()metodo del osmodulo insieme a un generatore (un generatore è un potente iteratore che mantiene il suo stato, ricordi?). Il codice seguente funziona bene con entrambe le versioni: Python 2 e Python 3.

Ecco un codice:

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)

Il listdir()metodo restituisce l'elenco delle voci per la directory specificata. Il metodo os.path.isfile()restituisce Truese la voce specificata è un file. E l' yieldoperatore chiude la funzione ma mantiene il suo stato corrente e restituisce solo il nome della voce rilevata come file. Tutto quanto sopra ci consente di passare in rassegna la funzione generatore.


11

Restituendo un elenco di percorsi file assoluti, non ricorre nelle sottodirectory

L = [os.path.join(os.getcwd(),f) for f in os.listdir('.') if os.path.isfile(os.path.join(os.getcwd(),f))]

2
Nota: os.path.abspath(f)sarebbe un sostituto un po 'più economico os.path.join(os.getcwd(),f).
ShadowRanger,

Sarei ancora più efficiente se avessi iniziato cwd = os.path.abspath('.'), poi usato al cwdposto di '.'e in os.getcwd()tutto per evitare un sacco di chiamate di sistema ridondanti.
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

Qui uso una struttura ricorsiva.


Lo stesso si può ottenere solo in una riga con pathlib:filter(Path.is_file, Path().rglob('*'))
Georgy,

9

Un saggio insegnante mi disse una volta che:

Quando ci sono diversi modi stabiliti per fare qualcosa, nessuno di loro è buono per tutti i casi.

Aggiungerò quindi una soluzione per un sottoinsieme del problema: abbastanza spesso, vogliamo solo verificare se un file corrisponde a una stringa iniziale e una stringa finale, senza andare nelle sottodirectory. Vorremmo quindi una funzione che restituisca un elenco di nomi di file, come:

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

Se ti interessa dichiarare prima due funzioni, puoi farlo:

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

Questa soluzione potrebbe essere facilmente generalizzata con espressioni regolari (e potresti voler aggiungere un patternargomento, se non vuoi che i tuoi pattern rimangano sempre all'inizio o alla fine del nome del file).


6

Utilizzando generatori

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)

4

Un'altra variante molto leggibile per Python 3.4+ è l'utilizzo di pathlib.Path.glob:

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

È semplice rendere più specifici, ad esempio cercare solo i file sorgente Python che non sono collegamenti simbolici, anche in tutte le sottodirectory:

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

3

Ecco la mia funzione generale per questo. Restituisce un elenco di percorsi di file piuttosto che nomi di file poiché l'ho trovato più utile. Ha alcuni argomenti opzionali che lo rendono versatile. Ad esempio, lo uso spesso con argomenti come pattern='*.txt'o 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)]

2

Fornirò un esempio di copertina in cui sourcepath e il tipo di file possono essere forniti come input. Il codice restituisce un elenco di nomi di file con estensione CSV. Usa . nel caso in cui tutti i file debbano essere restituiti. Ciò analizzerà anche ricorsivamente le sottodirectory.

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

Modificare le estensioni dei file e il percorso di origine secondo necessità.


1
Se hai intenzione di usare glob, usa semplicemente glob('**/*.csv', recursive=True). Non è necessario combinare questo con os.walk()recurse ( recursivee **sono supportati da Python 3.5).
Martijn Pieters

2

Per python2: pip installa rglob

import rglob
file_list=rglob.rglob("/home/base/dir/", "*")
print file_list

2

dircache è " Obsoleto dalla versione 2.6: Il modulo dircache è stato rimosso in 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

17
dirchache è " Obsoleto dalla versione 2.6: Il modulo dircache è stato rimosso in Python 3.0."
Daniel Reis,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.