Suchen Sie in Python alle Dateien in einem Verzeichnis mit der Erweiterung .txt

1043

Wie finde ich alle Dateien in einem Verzeichnis mit der Erweiterung .txtin Python?

Usertest
quelle

Antworten:

2354

Sie können verwenden glob:

import glob, os
os.chdir("/mydir")
for file in glob.glob("*.txt"):
    print(file)

oder einfach os.listdir:

import os
for file in os.listdir("/mydir"):
    if file.endswith(".txt"):
        print(os.path.join("/mydir", file))

oder wenn Sie das Verzeichnis durchlaufen möchten, verwenden Sie os.walk:

import os
for root, dirs, files in os.walk("/mydir"):
    for file in files:
        if file.endswith(".txt"):
             print(os.path.join(root, file))
Ghostdog74
quelle
11
Wie würden Sie mit Lösung 2 eine Datei oder Liste mit diesen Informationen erstellen?
Merlin
72
@ Ghostdog74: Meiner Meinung nach wäre es angemessener zu schreiben for file in fals für, for files in fda die Variable einen einzelnen Dateinamen enthält. Noch besser wäre es, die fto- filesund dann die for-Schleifen zu ändern for file in files.
Martineau
45
@computermacgyver: Nein, fileist kein reserviertes Wort, sondern nur der Name einer vordefinierten Funktion. Daher ist es durchaus möglich, es als Variablennamen in Ihrem eigenen Code zu verwenden. Obwohl es stimmt, dass solche Kollisionen im Allgemeinen vermieden werden sollten, fileist dies ein Sonderfall, da es kaum erforderlich ist, sie zu verwenden, weshalb häufig eine Ausnahme von der Richtlinie in Betracht gezogen wird. Wenn Sie dies nicht möchten, empfiehlt PEP8, solchen Namen einen einzelnen Unterstrich hinzuzufügen, dh file_, dem Sie zustimmen müssen, dass er immer noch gut lesbar ist.
Martineau
9
Danke, Martineau, du hast absolut Recht. Ich bin zu schnell zu Schlussfolgerungen gesprungen.
Computermacgyver
40
Ein pythonischerer Weg für # 2 kann für die Datei in [f für f in os.listdir ('/ mydir') sein, wenn f.endswith ('. Txt')]:
ozgur
247

Verwenden Sie glob .

>>> import glob
>>> glob.glob('./*.txt')
['./outline.txt', './pip-log.txt', './test.txt', './testingvim.txt']
Muhammad Alkarouri
quelle
Dies ist nicht nur einfach, es wird auch die Groß- und Kleinschreibung nicht berücksichtigt. (Zumindest ist es unter Windows, wie es sein sollte. Ich bin nicht sicher über andere Betriebssysteme.)
Jon Coombs
35
Beachten Sie, dass globDateien nicht rekursiv gefunden werden können, wenn Ihr Python unter 3.5 liegt. Weitere Informationen
Qun
Das Beste daran ist, dass Sie den Test für reguläre Ausdrücke verwenden können * .txt
Alex Punnen
@ JonCoombs nein. Zumindest nicht unter Linux.
Karuhanga
157

So etwas sollte den Job machen

for root, dirs, files in os.walk(directory):
    for file in files:
        if file.endswith('.txt'):
            print file
Adam Byrtek
quelle
73
+1 für die Benennung Ihrer Variablen root, dirs, filesanstelle von r, d, f. Viel besser lesbar.
Clément
27
Beachten Sie, dass hier zwischen Groß- und Kleinschreibung unterschieden wird (nicht mit .TXT oder .Txt übereinstimmt). Daher sollten Sie dies wahrscheinlich tun, wenn file.lower (). Endetwith ('.txt'):
Jon Coombs
1
Ihre Antwort befasst sich mit dem Unterverzeichnis.
Sam Liao
117

So etwas wird funktionieren:

>>> import os
>>> path = '/usr/share/cups/charmaps'
>>> text_files = [f for f in os.listdir(path) if f.endswith('.txt')]
>>> text_files
['euc-cn.txt', 'euc-jp.txt', 'euc-kr.txt', 'euc-tw.txt', ... 'windows-950.txt']
Seth
quelle
Wie würde ich den Pfad zu den text_files speichern? ['path / euc-cn.txt', ... 'path / windows-950.txt']
IceQueeny
5
Sie können os.path.joinfür jedes Element von verwenden text_files. Es könnte so etwas sein text_files = [os.path.join(path, f) for f in os.listdir(path) if f.endswith('.txt')].
Seth
55

Sie können einfach pathlibs 1 verwenden :glob

import pathlib

list(pathlib.Path('your_directory').glob('*.txt'))

oder in einer Schleife:

for txt_file in pathlib.Path('your_directory').glob('*.txt'):
    # do something with "txt_file"

Wenn Sie es rekursiv wollen, können Sie verwenden .glob('**/*.txt)


1 Das pathlibModul wurde in die Standardbibliothek in Python 3.4 aufgenommen. Sie können Back-Ports dieses Moduls jedoch auch auf älteren Python-Versionen installieren (z. B. mit condaoder pip): pathlibund pathlib2.

MSeifert
quelle
**/*.txtwird von älteren Python-Versionen nicht unterstützt. Also habe ich dies gelöst mit: foundfiles= subprocess.check_output("ls **/*.txt", shell=True) for foundfile in foundfiles.splitlines(): print foundfile
Roman
1
@ Roman Ja, es war nur ein Schaufenster, was zu pathlibtun ist, und ich habe bereits die Python-Versionsanforderungen aufgenommen. :) Aber wenn Ihr Ansatz noch nicht veröffentlicht wurde, fügen Sie ihn doch einfach als weitere Antwort hinzu.
MSeifert
1
Ja, das Posten einer Antwort hätte mir definitiv bessere Formatierungsmöglichkeiten gegeben. Ich poste es dort, weil ich denke, dass dies ein geeigneterer Ort dafür ist.
Roman
5
Beachten Sie, dass Sie diese Option auch verwenden können, rglobwenn Sie rekursiv nach Elementen suchen möchten. ZB.rglob('*.txt')
Bram Vanroy
40
import os

path = 'mypath/path' 
files = os.listdir(path)

files_txt = [i for i in files if i.endswith('.txt')]
user3281344
quelle
29

Ich mag os.walk () :

import os

for root, dirs, files in os.walk(dir):
    for f in files:
        if os.path.splitext(f)[1] == '.txt':
            fullpath = os.path.join(root, f)
            print(fullpath)

Oder mit Generatoren:

import os

fileiter = (os.path.join(root, f)
    for root, _, files in os.walk(dir)
    for f in files)
txtfileiter = (f for f in fileiter if os.path.splitext(f)[1] == '.txt')
for txt in txtfileiter:
    print(txt)
hughdbrown
quelle
28

Hier sind weitere Versionen derselben, die leicht unterschiedliche Ergebnisse liefern:

glob.iglob ()

import glob
for f in glob.iglob("/mydir/*/*.txt"): # generator, search immediate subdirectories 
    print f

glob.glob1 ()

print glob.glob1("/mydir", "*.tx?")  # literal_directory, basename_pattern

fnmatch.filter ()

import fnmatch, os
print fnmatch.filter(os.listdir("/mydir"), "*.tx?") # include dot-files
jfs
quelle
3
Für Neugierige gibt glob1()es eine Hilfsfunktion im globModul, die nicht in der Python-Dokumentation aufgeführt ist. Es gibt einige Inline-Kommentare, die beschreiben, was es in der Quelldatei tut, siehe .../Lib/glob.py.
Martineau
1
@martineau: glob.glob1()ist nicht öffentlich, aber verfügbar für Python 2.4-2.7; 3.0-3.2; Pypy; jython github.com/zed/test_glob1
jfs
1
Vielen Dank, das sind gute zusätzliche Informationen, wenn Sie entscheiden, ob Sie eine undokumentierte private Funktion in einem Modul verwenden möchten. ;-) Hier ist noch ein bisschen mehr. Die Python 2.7-Version ist nur 12 Zeilen lang und sieht so aus, als könnte sie leicht aus dem globModul extrahiert werden.
Martineau
21

path.py ist eine weitere Alternative: https://github.com/jaraco/path.py

from path import path
p = path('/path/to/the/directory')
for f in p.files(pattern='*.txt'):
    print f
Anuvrat Parashar
quelle
Cool, es akzeptiert auch reguläre Ausdrücke im Muster. Ich benutze for f in p.walk(pattern='*.txt')go durch alle Unterordner
Kostanos
1
Ja, es gibt auch Pathlib. Sie können etwas tun wie: list(p.glob('**/*.py'))
user2233949
15

Python v3.5 +

Schnelle Methode mit os.scandir in einer rekursiven Funktion. Sucht nach allen Dateien mit einer angegebenen Erweiterung in Ordnern und Unterordnern.

import os

def findFilesInFolder(path, pathList, extension, subFolders = True):
    """  Recursive function to find all files of an extension type in a folder (and optionally in all subfolders too)

    path:        Base directory to find files
    pathList:    A list that stores all paths
    extension:   File extension to find
    subFolders:  Bool.  If True, find files in all subfolders under path. If False, only searches files in the specified folder
    """

    try:   # Trapping a OSError:  File permissions problem I believe
        for entry in os.scandir(path):
            if entry.is_file() and entry.path.endswith(extension):
                pathList.append(entry.path)
            elif entry.is_dir() and subFolders:   # if its a directory, then repeat process as a nested function
                pathList = findFilesInFolder(entry.path, pathList, extension, subFolders)
    except OSError:
        print('Cannot access ' + path +'. Probably a permissions error')

    return pathList

dir_name = r'J:\myDirectory'
extension = ".txt"

pathList = []
pathList = findFilesInFolder(dir_name, pathList, extension, True)

Update April 2019

Wenn Sie über Verzeichnisse suchen, die 10.000 Dateien enthalten, wird das Anhängen an eine Liste ineffizient. Das Ergebnis zu erzielen ist eine bessere Lösung. Ich habe auch eine Funktion zum Konvertieren der Ausgabe in einen Pandas-Datenrahmen hinzugefügt.

import os
import re
import pandas as pd
import numpy as np


def findFilesInFolderYield(path,  extension, containsTxt='', subFolders = True, excludeText = ''):
    """  Recursive function to find all files of an extension type in a folder (and optionally in all subfolders too)

    path:               Base directory to find files
    extension:          File extension to find.  e.g. 'txt'.  Regular expression. Or  'ls\d' to match ls1, ls2, ls3 etc
    containsTxt:        List of Strings, only finds file if it contains this text.  Ignore if '' (or blank)
    subFolders:         Bool.  If True, find files in all subfolders under path. If False, only searches files in the specified folder
    excludeText:        Text string.  Ignore if ''. Will exclude if text string is in path.
    """
    if type(containsTxt) == str: # if a string and not in a list
        containsTxt = [containsTxt]

    myregexobj = re.compile('\.' + extension + '$')    # Makes sure the file extension is at the end and is preceded by a .

    try:   # Trapping a OSError or FileNotFoundError:  File permissions problem I believe
        for entry in os.scandir(path):
            if entry.is_file() and myregexobj.search(entry.path): # 

                bools = [True for txt in containsTxt if txt in entry.path and (excludeText == '' or excludeText not in entry.path)]

                if len(bools)== len(containsTxt):
                    yield entry.stat().st_size, entry.stat().st_atime_ns, entry.stat().st_mtime_ns, entry.stat().st_ctime_ns, entry.path

            elif entry.is_dir() and subFolders:   # if its a directory, then repeat process as a nested function
                yield from findFilesInFolderYield(entry.path,  extension, containsTxt, subFolders)
    except OSError as ose:
        print('Cannot access ' + path +'. Probably a permissions error ', ose)
    except FileNotFoundError as fnf:
        print(path +' not found ', fnf)

def findFilesInFolderYieldandGetDf(path,  extension, containsTxt, subFolders = True, excludeText = ''):
    """  Converts returned data from findFilesInFolderYield and creates and Pandas Dataframe.
    Recursive function to find all files of an extension type in a folder (and optionally in all subfolders too)

    path:               Base directory to find files
    extension:          File extension to find.  e.g. 'txt'.  Regular expression. Or  'ls\d' to match ls1, ls2, ls3 etc
    containsTxt:        List of Strings, only finds file if it contains this text.  Ignore if '' (or blank)
    subFolders:         Bool.  If True, find files in all subfolders under path. If False, only searches files in the specified folder
    excludeText:        Text string.  Ignore if ''. Will exclude if text string is in path.
    """

    fileSizes, accessTimes, modificationTimes, creationTimes , paths  = zip(*findFilesInFolderYield(path,  extension, containsTxt, subFolders))
    df = pd.DataFrame({
            'FLS_File_Size':fileSizes,
            'FLS_File_Access_Date':accessTimes,
            'FLS_File_Modification_Date':np.array(modificationTimes).astype('timedelta64[ns]'),
            'FLS_File_Creation_Date':creationTimes,
            'FLS_File_PathName':paths,
                  })

    df['FLS_File_Modification_Date'] = pd.to_datetime(df['FLS_File_Modification_Date'],infer_datetime_format=True)
    df['FLS_File_Creation_Date'] = pd.to_datetime(df['FLS_File_Creation_Date'],infer_datetime_format=True)
    df['FLS_File_Access_Date'] = pd.to_datetime(df['FLS_File_Access_Date'],infer_datetime_format=True)

    return df

ext =   'txt'  # regular expression 
containsTxt=[]
path = 'C:\myFolder'
df = findFilesInFolderYieldandGetDf(path,  ext, containsTxt, subFolders = True)
DougR
quelle
14

Python verfügt über alle Tools, um dies zu tun:

import os

the_dir = 'the_dir_that_want_to_search_in'
all_txt_files = filter(lambda x: x.endswith('.txt'), os.listdir(the_dir))
Xxxo
quelle
1
Wenn Sie möchten, dass all_txt_files eine Liste ist:all_txt_files = list(filter(lambda x: x.endswith('.txt'), os.listdir(the_dir)))
Ena
12

So rufen Sie alle '.txt'-Dateinamen im Ordner' dataPath 'pythonisch als Liste ab:

from os import listdir
from os.path import isfile, join
path = "/dataPath/"
onlyTxtFiles = [f for f in listdir(path) if isfile(join(path, f)) and  f.endswith(".txt")]
print onlyTxtFiles
ewalel
quelle
12

Versuchen Sie dies, um alle Ihre Dateien rekursiv zu finden:

import glob, os
os.chdir("H:\\wallpaper")# use whatever directory you want

#double\\ no single \

for file in glob.glob("**/*.txt", recursive = True):
    print(file)
Mayank
quelle
nicht mit rekursiver Version (Doppelstern :) **. Nur in Python 3 verfügbar. Was mir nicht gefällt, ist der chdirTeil. Keinen Bedarf.
Jean-François Fabre
2
filepath = os.path.join('wallpaper')Nun , Sie könnten die OS-Bibliothek verwenden, um den Pfad zu verbinden, z. B., und ihn dann als verwenden glob.glob(filepath+"**/*.psd", recursive = True), was das gleiche Ergebnis liefern würde.
Mitalee Rao
8
import os
import sys 

if len(sys.argv)==2:
    print('no params')
    sys.exit(1)

dir = sys.argv[1]
mask= sys.argv[2]

files = os.listdir(dir); 

res = filter(lambda x: x.endswith(mask), files); 

print res
mrgloom
quelle
8

Ich habe einen Test (Python 3.6.4, W7x64) durchgeführt, um festzustellen, welche Lösung für einen Ordner ohne Unterverzeichnisse am schnellsten ist, um eine Liste der vollständigen Dateipfade für Dateien mit einer bestimmten Erweiterung zu erhalten.

Um es kurz zu machen, diese Aufgabe os.listdir()ist die schnellste und 1,7-mal so schnell wie die nächstbeste: os.walk()(mit einer Pause!), 2,7-mal so schnell wie pathlib, 3,2-mal schneller als os.scandir()und 3,3-mal schneller als glob.
Bitte beachten Sie, dass sich diese Ergebnisse ändern, wenn Sie rekursive Ergebnisse benötigen. Wenn Sie eine der folgenden Methoden kopieren / einfügen, fügen Sie bitte eine .lower () hinzu, da sonst .EXT bei der Suche nach .ext nicht gefunden wird.

import os
import pathlib
import timeit
import glob

def a():
    path = pathlib.Path().cwd()
    list_sqlite_files = [str(f) for f in path.glob("*.sqlite")]

def b(): 
    path = os.getcwd()
    list_sqlite_files = [f.path for f in os.scandir(path) if os.path.splitext(f)[1] == ".sqlite"]

def c():
    path = os.getcwd()
    list_sqlite_files = [os.path.join(path, f) for f in os.listdir(path) if f.endswith(".sqlite")]

def d():
    path = os.getcwd()
    os.chdir(path)
    list_sqlite_files = [os.path.join(path, f) for f in glob.glob("*.sqlite")]

def e():
    path = os.getcwd()
    list_sqlite_files = [os.path.join(path, f) for f in glob.glob1(str(path), "*.sqlite")]

def f():
    path = os.getcwd()
    list_sqlite_files = []
    for root, dirs, files in os.walk(path):
        for file in files:
            if file.endswith(".sqlite"):
                list_sqlite_files.append( os.path.join(root, file) )
        break



print(timeit.timeit(a, number=1000))
print(timeit.timeit(b, number=1000))
print(timeit.timeit(c, number=1000))
print(timeit.timeit(d, number=1000))
print(timeit.timeit(e, number=1000))
print(timeit.timeit(f, number=1000))

Ergebnisse:

# Python 3.6.4
0.431
0.515
0.161
0.548
0.537
0.274
user136036
quelle
In der Dokumentation zu Python 3.6.5 heißt es: Die Funktion os.scandir () gibt Verzeichniseinträge zusammen mit Informationen zu Dateiattributen zurück und bietet in vielen gängigen Anwendungsfällen eine bessere Leistung [als os.listdir ()].
Bill Oldroyd
Mir fehlt der Skalierungsumfang dieses Tests. Wie viele Dateien haben Sie in diesem Test verwendet? Wie vergleichen sie, wenn Sie die Zahl nach oben / unten skalieren?
N4ppeL
5

Dieser Code macht mein Leben einfacher.

import os
fnames = ([file for root, dirs, files in os.walk(dir)
    for file in files
    if file.endswith('.txt') #or file.endswith('.png') or file.endswith('.pdf')
    ])
for fname in fnames: print(fname)
praba230890
quelle
5

Um ein Array von ".txt" -Dateinamen aus einem Ordner namens "data" im selben Verzeichnis abzurufen, verwende ich normalerweise diese einfache Codezeile:

import os
fileNames = [fileName for fileName in os.listdir("data") if fileName.endswith(".txt")]
Kamen Tsvetkov
quelle
3

Ich empfehle Ihnen, fnmatch und die obere Methode zu verwenden. Auf diese Weise können Sie Folgendes finden:

  1. Name. txt ;
  2. Name. TXT ;
  3. Name. TXT

.

import fnmatch
import os

    for file in os.listdir("/Users/Johnny/Desktop/MyTXTfolder"):
        if fnmatch.fnmatch(file.upper(), '*.TXT'):
            print(file)
Nicolaesse
quelle
3

Hier ist einer mit extend()

types = ('*.jpg', '*.png')
images_list = []
for files in types:
    images_list.extend(glob.glob(os.path.join(path, files)))
Efreeto
quelle
Nicht zur Verwendung mit .txt:)
Efreeto
2

Funktionslösung mit Unterverzeichnissen:

from fnmatch import filter
from functools import partial
from itertools import chain
from os import path, walk

print(*chain(*(map(partial(path.join, root), filter(filenames, "*.txt")) for root, _, filenames in walk("mydir"))))
Adam Chrapkowski
quelle
15
Ist dieser Code, den Sie langfristig beibehalten möchten?
Simeon Visser
2

Wenn der Ordner viele Dateien enthält oder der Speicher eine Einschränkung darstellt, sollten Sie Generatoren verwenden:

def yield_files_with_extensions(folder_path, file_extension):
   for _, _, files in os.walk(folder_path):
       for file in files:
           if file.endswith(file_extension):
               yield file

Option A: Iterieren

for f in yield_files_with_extensions('.', '.txt'): 
    print(f)

Option B: Holen Sie sich alle

files = [f for f in yield_files_with_extensions('.', '.txt')]
Taschuhka
quelle
2

Eine kopierbare Lösung ähnlich der von Ghostdog:

def get_all_filepaths(root_path, ext):
    """
    Search all files which have a given extension within root_path.

    This ignores the case of the extension and searches subdirectories, too.

    Parameters
    ----------
    root_path : str
    ext : str

    Returns
    -------
    list of str

    Examples
    --------
    >>> get_all_filepaths('/run', '.lock')
    ['/run/unattended-upgrades.lock',
     '/run/mlocate.daily.lock',
     '/run/xtables.lock',
     '/run/mysqld/mysqld.sock.lock',
     '/run/postgresql/.s.PGSQL.5432.lock',
     '/run/network/.ifstate.lock',
     '/run/lock/asound.state.lock']
    """
    import os
    all_files = []
    for root, dirs, files in os.walk(root_path):
        for filename in files:
            if filename.lower().endswith(ext):
                all_files.append(os.path.join(root, filename))
    return all_files
Martin Thoma
quelle
1

Verwenden Sie das Python OS- Modul, um Dateien mit einer bestimmten Erweiterung zu finden.

Das einfache Beispiel ist hier:

import os

# This is the path where you want to search
path = r'd:'  

# this is extension you want to detect
extension = '.txt'   # this can be : .jpg  .png  .xls  .log .....

for root, dirs_list, files_list in os.walk(path):
    for file_name in files_list:
        if os.path.splitext(file_name)[-1] == extension:
            file_name_path = os.path.join(root, file_name)
            print file_name
            print file_name_path   # This is the full path of the filter file
Rajiv Sharma
quelle
0

Viele Benutzer haben mit os.walkAntworten geantwortet , die alle Dateien, aber auch alle Verzeichnisse und Unterverzeichnisse sowie deren Dateien enthalten.

import os


def files_in_dir(path, extension=''):
    """
       Generator: yields all of the files in <path> ending with
       <extension>

       \param   path       Absolute or relative path to inspect,
       \param   extension  [optional] Only yield files matching this,

       \yield              [filenames]
    """


    for _, dirs, files in os.walk(path):
        dirs[:] = []  # do not recurse directories.
        yield from [f for f in files if f.endswith(extension)]

# Example: print all the .py files in './python'
for filename in files_in_dir('./python', '*.py'):
    print("-", filename)

Oder für einen Einzelfall, bei dem Sie keinen Generator benötigen:

path, ext = "./python", ext = ".py"
for _, _, dirfiles in os.walk(path):
    matches = (f for f in dirfiles if f.endswith(ext))
    break

for filename in matches:
    print("-", filename)

Wenn Sie Übereinstimmungen für etwas anderes verwenden möchten, möchten Sie möglicherweise eine Liste anstelle eines Generatorausdrucks erstellen:

    matches = [f for f in dirfiles if f.endswith(ext)]
kfsone
quelle
0

Eine einfache Methode mit forloop:

import os

dir = ["e","x","e"]

p = os.listdir('E:')  #path

for n in range(len(p)):
   name = p[n]
   myfile = [name[-3],name[-2],name[-1]]  #for .txt
   if myfile == dir :
      print(name)
   else:
      print("nops")

Dies kann jedoch verallgemeinert werden.

BoRRis
quelle
sehr unpythonische Art, eine Erweiterung zu überprüfen. Unsicher auch. Was ist, wenn der Name zu kurz ist? und warum eine Liste von Zeichen und keine Zeichenfolgen verwenden?
Jean-François Fabre