Wie liste ich alle Dateien eines Verzeichnisses auf?


Antworten:


4215

os.listdir()Sie erhalten alles, was sich in einem Verzeichnis befindet - Dateien und Verzeichnisse .

Wenn Sie nur Dateien möchten , können Sie diese entweder nach unten filtern os.path:

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

oder Sie können verwenden, os.walk()was zwei Listen für jedes Verzeichnis ergibt, das es besucht - Aufteilen in Dateien und Verzeichnisse für Sie. Wenn Sie nur das oberste Verzeichnis wollen, können Sie es einfach beim ersten Mal brechen

from os import walk

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

87
Ein bisschen einfacher: (_, _, filenames) = walk(mypath).next() (wenn Sie sicher sind, dass der Spaziergang mindestens einen Wert
zurückgibt

9
Leichte Änderung zum Speichern vollständiger Pfade: für (dirpath, dirnames, filenames) in os.walk (mypath): testsum_files.extend (os.path.join (dirpath, filename) für filename in filenames) break
okigan

150
f.extend(filenames)ist eigentlich nicht gleichbedeutend mit f = f + filenames. extendwird fan Ort und Stelle geändert, während durch Hinzufügen eine neue Liste an einem neuen Speicherort erstellt wird. Dies bedeutet extendim Allgemeinen effizienter als +, kann jedoch manchmal zu Verwirrung führen, wenn mehrere Objekte Verweise auf die Liste enthalten. Schließlich ist es erwähnenswert, dass f += filenamesdies nicht gleichbedeutend f.extend(filenames)ist . f = f + filenames
Benjamin Hodgson

30
@misterbee, Ihre Lösung ist die beste, nur eine kleine Verbesserung:_, _, filenames = next(walk(mypath), (None, None, []))
Bgusach

35
in Python 3.x verwenden(_, _, filenames) = next(os.walk(mypath))
ET-CS

1683

Ich bevorzuge die Verwendung des globModuls, da es Mustervergleich und -erweiterung durchführt.

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

Es wird eine Liste mit den abgefragten Dateien zurückgegeben:

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

17
Das ist eine Verknüpfung für listdir + fnmatch docs.python.org/library/fnmatch.html#fnmatch.fnmatch
Stefano

31
Zur Verdeutlichung gibt dies nicht den "vollständigen Pfad" zurück. es gibt einfach die Expansion des Glob zurück, was auch immer es sein mag. Beispiel gegeben /home/user/foo/bar/hello.txt, dann, wenn im Verzeichnis ausgeführt wird foo, die glob("bar/*.txt")angezeigt werden kann bar/hello.txt. Es gibt Fälle, in denen Sie tatsächlich den vollständigen (dh absoluten) Pfad möchten. Für diese Fälle siehe stackoverflow.com/questions/51520/…
michael

1
Verwandte: Finden Sie Dateien rekursiv mit glob: stackoverflow.com/a/2186565/4561887
Gabriel Staples

6
beantwortet diese Frage nicht. glob.glob("*")würde.
Jean-François Fabre

wunderschönen!!!! Also ... x=glob.glob("../train/*.png")werde mir eine Reihe meiner Pfade geben, solange ich den Namen des Ordners kenne. So cool!
Jennifer Crosby

858

Holen Sie sich eine Liste der Dateien mit Python 2 und 3


os.listdir()

So erhalten Sie alle Dateien (und Verzeichnisse) im aktuellen Verzeichnis (Python 3)

Im Folgenden finden Sie einfache Methoden zum Abrufen nur von Dateien im aktuellen Verzeichnis mithilfe von os und der listdir()Funktion in Python 3. Weitere Untersuchungen zeigen, wie Ordner im Verzeichnis zurückgegeben werden. Sie haben die Datei jedoch nicht im Unterverzeichnis kann zu Fuß gehen (später besprochen).

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

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

glob

Ich fand glob einfacher, die Datei des gleichen Typs oder mit etwas gemeinsamem auszuwählen. Schauen Sie sich das folgende Beispiel an:

import glob

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

glob mit Listenverständnis

import glob

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

glob mit einer Funktion

Die Funktion gibt eine Liste der angegebenen Erweiterung (.txt, .docx ecc.) Im Argument zurück

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 Erweiterung des vorherigen Codes

Die Funktion gibt jetzt eine Liste der Dateien zurück, die mit der Zeichenfolge übereinstimmen, die Sie als Argument übergeben

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

Ausgabe

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

Den vollständigen Pfadnamen mit abrufen os.path.abspath

Wie Sie bemerkt haben, haben Sie im obigen Code nicht den vollständigen Pfad der Datei. Wenn Sie den absoluten Pfad benötigen, können Sie eine andere Funktion des os.pathaufgerufenen Moduls verwenden _getfullpathnameund die Datei, aus der Sie sie erhalten, os.listdir()als Argument verwenden. Es gibt andere Möglichkeiten, den vollständigen Pfad zu erhalten, wie wir später überprüfen werden (ich habe, wie von mexmex vorgeschlagen, _getfullpathname durch ersetzt 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']

Holen Sie sich den vollständigen Pfadnamen eines Dateityps in alle Unterverzeichnisse mit walk

Ich finde das sehr nützlich, um Dinge in vielen Verzeichnissen zu finden, und es hat mir geholfen, eine Datei zu finden, an die ich mich nicht erinnern konnte:

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(): Dateien im aktuellen Verzeichnis abrufen (Python 2)

Wenn Sie in Python 2 die Liste der Dateien im aktuellen Verzeichnis anzeigen möchten, müssen Sie das Argument '.' oder os.getcwd () in der Methode os.listdir.

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

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

In den Verzeichnisbaum aufsteigen

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

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

Dateien abrufen: os.listdir()in einem bestimmten Verzeichnis (Python 2 und 3)

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

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

Holen Sie sich Dateien eines bestimmten Unterverzeichnisses mit os.listdir()

import os

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

os.walk('.') - Aktuelles Verzeichnis

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

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

next(os.walk('.')) und 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:\\') - Holen Sie sich den vollständigen Pfad - Listenverständnis

 [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 - Vollständigen Pfad abrufen - Alle Dateien in Unterverzeichnissen **

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() - Holen Sie sich nur TXT-Dateien

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

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

Verwenden Sie glob, um den vollständigen Pfad der Dateien abzurufen

Wenn ich den absoluten Pfad der Dateien benötigen sollte:

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

Verwenden os.path.isfile, um Verzeichnisse in der Liste zu vermeiden

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

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

Mit list comprehension:

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

Alternativ können Sie pathlib.Path()anstelle von verwendenpathlib.Path(".")

Verwenden Sie die glob-Methode 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

Holen Sie sich alle und nur Dateien mit 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']

Holen Sie sich nur Dateien mit next und gehen Sie in ein Verzeichnis

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

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

Holen Sie sich nur Verzeichnisse mit next und gehen Sie in ein Verzeichnis

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

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

Holen Sie sich alle Unterverzeichnisnamen mit 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() ab Python 3.5 und höher

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

Beispiele:

Ex. 1: Wie viele Dateien befinden sich in den Unterverzeichnissen?

In diesem Beispiel suchen wir nach der Anzahl der Dateien, die in allen Verzeichnissen und deren Unterverzeichnissen enthalten sind.

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'

Beispiel 2: Wie kopiere ich alle Dateien von einem Verzeichnis in ein anderes?

Ein Skript, mit dem Sie auf Ihrem Computer alle Dateien eines Typs (Standard: pptx) suchen und in einen neuen Ordner kopieren können.

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: So erhalten Sie alle Dateien in einer txt-Datei

Falls Sie eine txt-Datei mit allen Dateinamen erstellen möchten:

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

Beispiel: txt mit allen Dateien einer Festplatte

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

Die gesamte Datei von C: \ in einer Textdatei

Dies ist eine kürzere Version des vorherigen Codes. Ändern Sie den Ordner, in dem die Dateien gesucht werden sollen, wenn Sie von einer anderen Position aus starten müssen. Dieser Code generiert eine 50-MB-Textdatei auf meinem Computer mit weniger als 500.000 Zeilen mit Dateien mit dem vollständigen Pfad.

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

So schreiben Sie eine Datei mit allen Pfaden in einen Ordner eines Typs

Mit dieser Funktion können Sie eine txt-Datei erstellen, die den Namen eines Dateityps enthält, nach dem Sie suchen (z. B. pngfile.txt), und den vollständigen Pfad aller Dateien dieses Typs enthält. Es kann manchmal nützlich sein, denke ich.

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

(Neu) Finde alle Dateien und öffne sie mit der tkinter GUI

Ich wollte in diesem Jahr 2019 nur eine kleine App hinzufügen, um nach allen Dateien in einem Verzeichnis zu suchen und sie durch Doppelklicken auf den Namen der Datei in der Liste öffnen zu können. Geben Sie hier die Bildbeschreibung ein

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
Dies ist eine Mischung aus zu vielen Antworten auf Fragen, die hier nicht gestellt werden. Es kann auch sinnvoll sein, die Vorbehalte oder empfohlenen Ansätze zu erläutern. Ich bin nicht besser dran, einen Weg zu kennen als 20 Wege, um dasselbe zu tun, es sei denn, ich weiß auch, welcher Zeitpunkt besser geeignet ist.
cs95

Ok, so schnell wie möglich werde ich mir meine Antwort ansehen und versuchen, sie sauberer und mit nützlicheren Informationen über den Unterschied zwischen den Methoden usw. zu gestalten.
Giovanni G. PY

Sie sollten die Dateierweiterung nicht ermitteln, indem Sie überprüfen, ob der Dateiname eine Teilzeichenfolge enthält. Das könnte viele Probleme verursachen. Ich empfehle immer zu überprüfen, ob der Dateiname mit dem jeweiligen Teilstring endet.
ni1ight

Ok, @ n1light Ich habe den Code geändert ...
Giovanni G. PY

811
import os
os.listdir("somedirectory")

gibt eine Liste aller Dateien und Verzeichnisse in "somedirectory" zurück.


11
Dies gibt den relativen Pfad der Dateien zurück, verglichen mit dem vollständigen Pfad, der vonglob.glob
xji

22
@JIXiang: Gibt os.listdir()immer nur Dateinamen zurück (keine relativen Pfade). Was glob.glob()zurückkehrt, hängt vom Pfadformat des Eingabemusters ab.
mklement0

os.listdir () -> Es werden immer das Verzeichnis und die Datei am angegebenen Speicherort aufgelistet. Gibt es eine Möglichkeit, nur Verzeichnisse und keine Dateien aufzulisten?
RonyA

160

Eine einzeilige Lösung, um nur eine Liste von Dateien (keine Unterverzeichnisse) abzurufen:

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

oder absolute Pfadnamen:

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

7
Nur ein Einzeiler, wenn Sie bereits haben import os. Scheint weniger prägnant als glob()für mich.
ArtOfWarfare

4
Problem mit glob ist, dass ein Ordner mit dem Namen 'Something.something' von glob ('/ home / adam /*.*') zurückgegeben wird
Remi

6
Unter OS X gibt es ein sogenanntes Bundle. Es ist ein Verzeichnis, das im Allgemeinen als Datei behandelt werden sollte (wie eine .tar). Möchten Sie, dass diese als Datei oder Verzeichnis behandelt werden? Die Verwendung glob()würde es als Datei behandeln. Ihre Methode würde es als Verzeichnis behandeln.
ArtOfWarfare

132

Abrufen vollständiger Dateipfade aus einem Verzeichnis und allen seinen Unterverzeichnissen

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

  • Der Pfad, den ich in der obigen Funktion angegeben habe, enthielt drei Dateien - zwei davon im Stammverzeichnis und eine weitere in einem Unterordner namens "SUBFOLDER". Sie können jetzt Dinge tun wie:
  • print full_file_paths welches die Liste druckt:

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

Wenn Sie möchten, können Sie den Inhalt öffnen und lesen oder sich nur auf Dateien mit der Erweiterung ".dat" konzentrieren, wie im folgenden Code beschrieben:

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

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


Dies ist die einzige Antwort.
Lernende

78

Seit Version 3.4 gibt es dafür eingebaute Iteratoren, die viel effizienter sind als os.listdir():

pathlib: Neu in Version 3.4.

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

Gemäß PEP 428 besteht das Ziel der pathlibBibliothek darin, eine einfache Hierarchie von Klassen bereitzustellen, um Dateisystempfade und die allgemeinen Operationen, die Benutzer über sie ausführen, zu handhaben.

os.scandir(): Neu in Version 3.5.

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

Beachten Sie, dass os.walk()verwendet os.scandir()statt os.listdir()von 2-20 mal nach erhöht wurde von Version 3.5, und seine Geschwindigkeit 471 PEP .

Lassen Sie mich auch empfehlen, den Kommentar von ShadowRanger unten zu lesen.


1
Vielen Dank! Ich denke, es ist die einzige Lösung, die nicht direkt zurückkehrt list. Könnte alternativ p.nameanstelle der ersten verwendet werden, pwenn dies bevorzugt wird.
Jeromej

1
Herzlich willkommen! Ich würde es vorziehen zu generierenpathlib.Path() Instanzen zu da sie viele nützliche Methoden haben, mit denen ich keinen Abfall verschwenden möchte. Sie können str(p)sie auch für Pfadnamen aufrufen .
SzieberthAdam

6
Hinweis: Die os.scandirLösung ist effizienter als os.listdirbei einer os.path.is_filePrüfung oder Ähnlichem, selbst wenn Sie eine benötigen list(damit Sie nicht von einer verzögerten Iteration profitieren), da os.scandirvom Betriebssystem bereitgestellte APIs verwendet werden, mit denen Sie die is_fileInformationen während der Iteration kostenlos erhalten , überhaupt kein Roundtrip pro Datei auf die Festplatte zu statihnen (unter Windows DirEntryerhalten Sie statkostenlos vollständige Informationen, auf * NIX-Systemen, die statfür weitere Informationen erforderlich sindis_file , is_dirusw., aber DirEntryCaches auf den ersten der statEinfachheit halber).
ShadowRanger

1
Sie können auch verwenden entry.name nur den Dateinamen oder entry.pathden vollständigen Pfad abrufen. Nicht mehr überall os.path.join ().
user136036

56

Vorbemerkungen

  • Obwohl es im Fragetext eine klare Unterscheidung zwischen Datei- und Verzeichnisbegriffen gibt , können einige argumentieren, dass Verzeichnisse tatsächlich spezielle Dateien sind
  • Die Anweisung " Alle Dateien eines Verzeichnisses " kann auf zwei Arten interpretiert werden:
    1. Nur alle direkten (oder Level 1) Nachkommen
    2. Alle Nachkommen im gesamten Verzeichnisbaum (einschließlich derjenigen in Unterverzeichnissen)
  • Als die Frage gestellt wurde, stelle ich mir vor, dass Python 2 die LTS- Version war, die Codebeispiele werden jedoch von Python 3 ( .5 ) ausgeführt (ich werde sie so Python 2- konform wie möglich halten; auch jeden dazugehörigen Code Python , das ich veröffentlichen werde, stammt aus Version 3.5.4 (sofern nicht anders angegeben). Dies hat Konsequenzen im Zusammenhang mit einem anderen Schlüsselwort in der Frage: " Fügen Sie sie einer Liste hinzu ":

    • In Versionen vor Python 2.2 wurden Sequenzen (Iterables) hauptsächlich durch Listen (Tupel, Mengen, ...) dargestellt.
    • In Python 2.2 ist das Konzept von Generators ( [Python.Wiki]: Generators ) - mit freundlicher Genehmigung von [Python 3]: The Yield Statement ) eingeführt. Im Laufe der Zeit wurden Generator-Gegenstücke für Funktionen angezeigt, die Listen zurückgaben / mit ihnen arbeiteten
    • In Python 3 ist der Generator das Standardverhalten
    • Sie sind sich nicht sicher, ob die Rückgabe einer Liste weiterhin obligatorisch ist (oder auch ein Generator), aber wenn Sie einen Generator an den Listenkonstruktor übergeben , wird daraus eine Liste erstellt (und auch verbraucht). Das folgende Beispiel zeigt die Unterschiede in [Python 3]: map ( Funktion, iterierbar, ... )
    >>> 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'>)
  • Die Beispiele basieren auf einem Verzeichnis namens root_dir mit der folgenden Struktur (dieses Beispiel ist für Win , aber ich verwende denselben Baum auch auf 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


Lösungen

Programmatische Ansätze:

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

    Gibt eine Liste mit den Namen der Einträge in dem durch path angegebenen Verzeichnis zurück. Die Liste ist in beliebiger Reihenfolge und enthält keine speziellen Einträge '.'und '..'...


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

    Ein ausführlicheres Beispiel ( 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()

    Anmerkungen :

    • Es gibt zwei Implementierungen:
      • Eine, die Generatoren verwendet (hier scheint es natürlich nutzlos zu sein, da ich das Ergebnis sofort in eine Liste konvertiere)
      • Der klassische (Funktionsnamen, die auf _old enden )
    • Rekursion wird verwendet (um in Unterverzeichnisse zu gelangen)
    • Für jede Implementierung gibt es zwei Funktionen:
      • Eine, die mit einem Unterstrich ( _ ) beginnt : "privat" (sollte nicht direkt aufgerufen werden) - das erledigt die ganze Arbeit
      • Der öffentliche (Wrapper gegenüber dem vorherigen): Er entfernt nur den anfänglichen Pfad (falls erforderlich) von den zurückgegebenen Einträgen. Es ist eine hässliche Implementierung, aber es ist die einzige Idee, mit der ich an dieser Stelle kommen könnte
    • In Bezug auf die Leistung sind Generatoren im Allgemeinen etwas schneller (sowohl unter Berücksichtigung der Erstellungs- als auch der Iterationszeiten ), aber ich habe sie nicht in rekursiven Funktionen getestet und iteriere auch innerhalb der Funktion über innere Generatoren - ich weiß nicht, wie die Leistung ist freundlich ist das
    • Spielen Sie mit den Argumenten, um unterschiedliche Ergebnisse zu erzielen


    Ausgabe :

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

    Gibt einen Iterator von os.DirEntry- Objekten zurück, der den Einträgen in dem durch path angegebenen Verzeichnis entspricht . Die Einträge werden in beliebiger Reihenfolge und die speziellen Einträge ausgegeben '.'und '..'sind nicht enthalten.

    Die Verwendung von scandir () anstelle von listdir () kann die Leistung von Code, der auch Dateityp- oder Dateiattributinformationen benötigt, erheblich verbessern , da os.DirEntry- Objekte diese Informationen verfügbar machen , wenn das Betriebssystem sie beim Scannen eines Verzeichnisses bereitstellt. Alle os.DirEntry- Methoden führen möglicherweise einen Systemaufruf aus, aber is_dir () und is_file () erfordern normalerweise nur einen Systemaufruf für symbolische Links. os.DirEntry.stat () erfordert unter Unix immer einen Systemaufruf, unter Windows jedoch nur einen für symbolische Links.


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

    Anmerkungen :

    • Es ist ähnlich wie os.listdir
    • Es ist aber auch flexibler (und bietet mehr Funktionalität), mehr Python- IC (und in einigen Fällen schneller)


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

    Generieren Sie die Dateinamen in einem Verzeichnisbaum, indem Sie den Baum entweder von oben nach unten oder von unten nach oben durchlaufen. Für jedes Verzeichnis in dem Verzeichnisbaum am wurzelt oben (einschließlich der oben selbst), es ergibt sich ein 3-Tupel ( 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', [], [])

    Anmerkungen :

    • Unter den Kulissen wird es verwendet os.scandir( os.listdirbei älteren Versionen)
    • Es erledigt das schwere Heben, indem es in Unterordnern wiederholt wird


  1. [Python 3]: glob. glob ( Pfadname, *, rekursiv = falsch ) ( [Python 3]: glob. iglob ( Pfadname, *, rekursiv = falsch ) )

    Gibt eine möglicherweise leere Liste von Pfadnamen zurück , die mit dem Pfadnamen übereinstimmen. Dies muss eine Zeichenfolge sein, die eine Pfadspezifikation enthält. Der Pfadname kann entweder absolut (wie /usr/src/Python-1.5/Makefile) oder relativ (wie ../../Tools/*/*.gif) sein und Platzhalter im Shell-Stil enthalten. Unterbrochene Symlinks sind in den Ergebnissen enthalten (wie in der Shell).
    ...
    geändert in Version 3.5 : Unterstützung für rekursive Globs mit " **".


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

    Anmerkungen :

    • Verwendet os.listdir
    • Bei großen Bäumen (insbesondere wenn rekursiv aktiviert ist ) wird Iglob bevorzugt
    • Ermöglicht erweiterte Filterung basierend auf dem Namen (aufgrund des Platzhalters)


  1. [Python 3]: Klassenpfad. Pfad ( * Pfadsegmente ) ( 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']

    Anmerkungen :

    • Dies ist ein Weg, um unser Ziel zu erreichen
    • Es ist der OOP- Stil für die Behandlung von Pfaden
    • Bietet viele Funktionen


  1. [Python 2]: dircache.listdir (Pfad) (nur 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) über [Python 3]: ctypes - Eine Fremdfunktionsbibliothek für Python ( POSIX- spezifisch)

    ctypes ist eine Fremdfunktionsbibliothek für Python. Es bietet C-kompatible Datentypen und ermöglicht das Aufrufen von Funktionen in DLLs oder gemeinsam genutzten Bibliotheken. Es kann verwendet werden, um diese Bibliotheken in reines Python zu verpacken.

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

    Anmerkungen :

    • Es lädt die drei Funktionen aus libc (im aktuellen Prozess geladen) und ruft sie auf (für weitere Details überprüfen Sie [SO]: Wie überprüfe ich, ob eine Datei ohne Ausnahmen vorhanden ist? (Antwort von @ CristiFati) - letzte Notizen von Punkt 4. ). Dies würde diesen Ansatz sehr nahe an der Python / C- Kante platzieren
    • LinuxDirent64 ist die ctypes- Darstellung von struct dirent64 aus [man7]: dirent.h (0P) (ebenso wie die DT_- Konstanten) von meinem Computer: Ubtu 16 x64 ( 4.10.0-40-generic und libc6-dev: amd64 ). Bei anderen Varianten / Versionen kann die Strukturdefinition abweichen. In diesem Fall sollte der Alias ctypes aktualisiert werden, da sonst undefiniertes Verhalten angezeigt wird
    • Es gibt Daten im os.walkFormat zurück. Ich habe mich nicht darum gekümmert, es rekursiv zu machen, aber ausgehend vom vorhandenen Code wäre das eine ziemlich triviale Aufgabe
    • Auch unter Win ist alles machbar , die Daten (Bibliotheken, Funktionen, Strukturen, Konstanten, ...) unterscheiden sich


    Ausgabe :

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

    Ruft mithilfe der Windows-Unicode-API eine Liste übereinstimmender Dateinamen ab. Eine Schnittstelle zur API FindFirstFileW / FindNextFileW / Find close Funktionen.


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

    Anmerkungen :


  1. Installieren Sie ein (anderes) Paket eines Drittanbieters, das den Trick ausführt
    • Wird sich höchstwahrscheinlich auf eine (oder mehrere) der oben genannten Methoden stützen (möglicherweise mit geringfügigen Anpassungen).


Anmerkungen :

  • Der Code soll tragbar (mit Ausnahme von Orten, die auf einen bestimmten Bereich abzielen - die markiert sind) oder kreuzweise sein:

    • Plattform ( Nix , Win ,)
    • Python- Version (2, 3,)
  • In den obigen Varianten wurden mehrere Pfadstile (absolut, Verwandte) verwendet, um die Tatsache zu veranschaulichen, dass die verwendeten "Werkzeuge" in dieser Richtung flexibel sind

  • os.listdirund os.scandirbenutze opendir / readdir / closedir ( [MS.Docs]: FindFirstFileW-Funktion / [MS.Docs]: FindNextFileW-Funktion / [MS.Docs]: FindClose-Funktion ) (über [GitHub]: python / cpython - (master) cpython / Module / posixmodule.c )

  • win32file.FindFilesWverwendet auch diese ( Win- spezifischen) Funktionen (über [GitHub]: mhammond / pywin32 - (master) pywin32 / win32 / src / win32file.i )

  • _get_dir_content (ab Punkt 1 ) kann mit jedem dieser Ansätze implementiert werden (einige erfordern mehr Arbeit und andere weniger).

    • Es könnte eine erweiterte Filterung (anstelle von nur Datei vs. Verzeichnis) durchgeführt werden: z. B. könnte das Argument include_folders durch ein anderes ersetzt werden (z. B. filter_func ). Dies wäre eine Funktion, die einen Pfad als Argument verwendet: filter_func=lambda x: True(dies wird nicht entfernt alles) und in _get_dir_content so etwas wie: if not filter_func(entry_with_path): continue(Wenn die Funktion für einen Eintrag fehlschlägt, wird sie übersprungen), aber je komplexer der Code wird, desto länger dauert die Ausführung
  • Nota bene! Da die Rekursion verwendet wird, muss ich erwähnen, dass ich einige Tests auf meinem Laptop ( Win 10 x64 ) durchgeführt habe, die völlig unabhängig von diesem Problem waren, und als die Rekursionsstufe Werte irgendwo im Bereich (990 .. 1000) erreichte ( Rekursionslimit - 1000) (Standard)), ich habe StackOverflow :). Wenn der Verzeichnisbaum diese Grenze überschreitet (ich bin kein FS- Experte, daher weiß ich nicht, ob dies überhaupt möglich ist), könnte dies ein Problem sein.
    Ich muss auch erwähnen, dass ich nicht versucht habe, das Rekursionslimit zu erhöhen, da ich keine Erfahrung in diesem Bereich habe (wie viel kann ich erhöhen, bevor ich auch den Stack unter OS erhöhen mussLevel), aber theoretisch besteht immer die Möglichkeit eines Ausfalls, wenn die Dir-Tiefe größer ist als das höchstmögliche Rekursionslimit (auf dieser Maschine).

  • Die Codebeispiele dienen nur zu Demonstrationszwecken. Das bedeutet, dass ich die Fehlerbehandlung nicht berücksichtigt habe (ich glaube, es gibt keinen Versuch / außer / else / finally- Block), daher ist der Code nicht robust (der Grund ist: ihn so einfach und kurz wie möglich zu halten ). Für die Produktion sollte auch die Fehlerbehandlung hinzugefügt werden

Andere Ansätze:

  1. Verwenden Sie Python nur als Wrapper

    • Alles wird mit einer anderen Technologie erledigt
    • Diese Technologie wird von Python aufgerufen
    • Die bekannteste Variante, die ich kenne, ist der sogenannte Systemadministrator- Ansatz:

      • Verwenden Sie Python (oder eine andere Programmiersprache), um Shell- Befehle auszuführen (und deren Ausgaben zu analysieren).
      • Einige halten dies für einen ordentlichen Hack
      • Ich halte es eher wie eine lahme Abhilfe ( gainarie ), da die Aktion an sich aus durchgeführt wird , Shell ( cmd in diesem Fall), und somit nichts mit dem zu tun hat Python .
      • Das Filtern ( grep/ findstr) oder das Formatieren der Ausgabe könnte auf beiden Seiten erfolgen, aber ich werde nicht darauf bestehen. Auch habe ich absichtlich os.systemstatt 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

    Im Allgemeinen ist dieser Ansatz zu vermeiden, da der Parsing-Code ebenfalls angepasst werden sollte , wenn sich das Befehlsausgabeformat zwischen den Betriebssystemversionen / -varianten geringfügig unterscheidet . ganz zu schweigen von den Unterschieden zwischen den Gebietsschemas).


48

Ich wirklich mochte adamk Antwort , was darauf hindeutet , dass Sie verwenden glob(), aus dem Modul mit dem gleichen Namen. Auf diese Weise können Sie Muster mit *s abgleichen .

Aber wie andere Leute in den Kommentaren glob()betonten , kann man über inkonsistente Schrägstriche stolpern. Um dies zu unterstützen, schlage ich vor, dass Sie die Funktionen join()und expanduser()im os.pathModul und möglicherweise auch die getcwd()Funktion im osModul verwenden.

Als Beispiele:

from glob import glob

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

Das Obige ist schrecklich - der Pfad wurde fest codiert und funktioniert unter Windows immer nur zwischen dem Laufwerksnamen und dem \s, das im Pfad fest codiert ist.

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

Das Obige funktioniert besser, Usershängt jedoch vom Ordnernamen ab, der häufig unter Windows und nicht so häufig unter anderen Betriebssystemen gefunden wird. Es hängt auch davon ab, dass der Benutzer einen bestimmten Namen hat 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'))

Dies funktioniert perfekt auf allen Plattformen.

Ein weiteres großartiges Beispiel, das plattformübergreifend perfekt funktioniert und etwas anderes macht:

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

Ich hoffe, diese Beispiele helfen Ihnen dabei, die Leistungsfähigkeit einiger Funktionen zu erkennen, die Sie in den Standardmodulen der Python-Bibliothek finden.


4
Zusätzlicher Glob-Spaß: Ab Python 3.5 **funktioniert dies, solange Sie es einstellen recursive = True. Siehe die Dokumente hier: 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 

Vielen Dank! funktioniert! perfekt!
Ambigus9 vor

23

Wenn Sie nach einer Python-Implementierung von find suchen , ist dies ein Rezept, das ich ziemlich häufig verwende:

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

Also habe ich ein PyPI- Paket daraus gemacht und es gibt auch ein GitHub-Repository . Ich hoffe, dass jemand es möglicherweise nützlich für diesen Code findet.


14

Für bessere Ergebnisse können Sie die listdir()Methode des osModuls zusammen mit einem Generator verwenden (ein Generator ist ein leistungsstarker Iterator, der seinen Status beibehält, erinnern Sie sich?). Der folgende Code funktioniert mit beiden Versionen einwandfrei: Python 2 und Python 3.

Hier ist ein 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)

Die listdir()Methode gibt die Liste der Einträge für das angegebene Verzeichnis zurück. Die Methode gibt os.path.isfile()zurück, Truewenn der angegebene Eintrag eine Datei ist. Der yieldOperator beendet die Funktion, behält jedoch seinen aktuellen Status bei und gibt nur den Namen des als Datei erkannten Eintrags zurück. All dies ermöglicht es uns, die Generatorfunktion zu durchlaufen.


11

Das Zurückgeben einer Liste absoluter Dateipfade erfolgt nicht in Unterverzeichnissen

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

2
Hinweis: os.path.abspath(f)wäre ein etwas billigerer Ersatz für os.path.join(os.getcwd(),f).
ShadowRanger

Ich wäre noch effizienter, wenn Sie damit beginnen cwd = os.path.abspath('.')und dann cwdanstelle von '.'und os.getcwd()durchgehend verwenden würden, um viele redundante Systemaufrufe zu vermeiden.
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

Hier verwende ich eine rekursive Struktur.


Das gleiche kann nur in einer Zeile erreicht werden mit pathlib:filter(Path.is_file, Path().rglob('*'))
Georgy

9

Ein weiser Lehrer sagte mir einmal:

Wenn es mehrere etablierte Möglichkeiten gibt, etwas zu tun, ist keine davon für alle Fälle gut.

Ich werde daher eine Lösung für eine Teilmenge des Problems hinzufügen : Oft möchten wir nur prüfen, ob eine Datei mit einer Startzeichenfolge und einer Endzeichenfolge übereinstimmt, ohne in Unterverzeichnisse zu wechseln. Wir möchten daher eine Funktion, die eine Liste von Dateinamen zurückgibt, wie:

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

Wenn Sie zuerst zwei Funktionen deklarieren möchten, können Sie dies tun:

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

Diese Lösung kann leicht mit regulären Ausdrücken verallgemeinert werden (und Sie möchten möglicherweise ein patternArgument hinzufügen , wenn Ihre Muster nicht immer am Anfang oder Ende des Dateinamens bleiben sollen).


6

Generatoren verwenden

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

Eine andere gut lesbare Variante für Python 3.4+ ist die Verwendung von pathlib.Path.glob:

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

Es ist einfach, genauer zu machen, z. B. nur in allen Unterverzeichnissen nach Python-Quelldateien zu suchen, die keine symbolischen Links sind:

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

3

Hier ist meine Allzweckfunktion dafür. Es gibt eine Liste von Dateipfaden anstelle von Dateinamen zurück, da ich dies als nützlicher empfand. Es gibt einige optionale Argumente, die es vielseitig machen. Zum Beispiel benutze ich es oft mit Argumenten wie pattern='*.txt'oder 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

Ich werde ein Beispiel für einen Liner bereitstellen, in dem Quellpfad und Dateityp als Eingabe angegeben werden können. Der Code gibt eine Liste von Dateinamen mit der Erweiterung csv zurück. Verwenden Sie . falls alle Dateien zurückgegeben werden müssen. Dadurch werden auch die Unterverzeichnisse rekursiv durchsucht.

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

Ändern Sie die Dateierweiterungen und den Quellpfad nach Bedarf.


1
Wenn Sie verwenden möchten, verwenden Sie globeinfach glob('**/*.csv', recursive=True). Keine Notwendigkeit, dies mit zu kombinieren, um os.walk()zu rekursieren ( recursiveund **werden seit Python 3.5 unterstützt).
Martijn Pieters

2

Für python2: pip installiere rglob

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

2

dircache ist "Veraltet seit Version 2.6: Das dircache-Modul wurde in Python 3.0 entfernt."

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 ist "Veraltet seit Version 2.6: Das dircache-Modul wurde in Python 3.0 entfernt."
Daniel Reis
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.