Trova tutti i file in una directory con estensione .txt in Python


Risposte:


2359

Puoi usare glob:

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

o semplicemente os.listdir:

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

o se vuoi attraversare la directory, usa 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))

11
Utilizzando la soluzione n. 2, come creeresti un file o un elenco con tali informazioni?
Merlin,

72
@ ghostdog74: Secondo me sarebbe più appropriato scrivere for file in fche per, for files in fpoiché ciò che è nella variabile è un singolo nome file. Ancora meglio sarebbe cambiare il fto filese quindi il for for loop potrebbe diventare for file in files.
martineau,

46
@computermacgyver: No, filenon è una parola riservata, è solo il nome di una funzione predefinita, quindi è del tutto possibile usarlo come nome di variabile nel proprio codice. Anche se è vero che generalmente si dovrebbero evitare collisioni del genere, fileè un caso speciale perché non c'è quasi mai bisogno di usarlo, quindi è spesso considerato un'eccezione alle linee guida. Se non vuoi farlo, PEP8 consiglia di aggiungere un singolo trattino basso a tali nomi, vale a dire file_, che dovresti concordare è ancora abbastanza leggibile.
martineau,

9
Grazie, martineau, hai assolutamente ragione. Ho saltato troppo rapidamente alle conclusioni.
computermacgyver,

40
Un modo più Pythonic per # 2 può essere per il file in [f per f in os.listdir ('/ mydir') se f.endswith ('. Txt')]:
ozgur

247

Usa glob .

>>> import glob
>>> glob.glob('./*.txt')
['./outline.txt', './pip-log.txt', './test.txt', './testingvim.txt']

Non solo è facile, ma non fa distinzione tra maiuscole e minuscole. (Almeno, è su Windows, come dovrebbe essere. Non sono sicuro di altri sistemi operativi.)
Jon Coombs

35
Fai attenzione a globnon riuscire a trovare i file in modo ricorsivo se il tuo python è inferiore a 3.5. maggiori informazioni
qun

la parte migliore è che puoi usare il test delle espressioni regolari * .txt
Alex Punnen il

@JonCoombs no. Almeno non su Linux.
Karuhanga,

157

Qualcosa del genere dovrebbe fare il lavoro

for root, dirs, files in os.walk(directory):
    for file in files:
        if file.endswith('.txt'):
            print file

73
+1 per nominare le variabili root, dirs, filesanziché r, d, f. Molto più leggibile.
Clément,

27
Nota che questo fa distinzione tra maiuscole e minuscole (non corrisponderà a .TXT o .Txt), quindi probabilmente vorrai fare se file.lower (). Limitswith ('. Txt'):
Jon Coombs

1
la tua risposta riguarda la sottodirectory.
Sam Liao,

117

Qualcosa del genere funzionerà:

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

Come vorrei salvare il percorso nei file di testo? ['path / euc-cn.txt', ... 'path / windows-950.txt']
IceQueeny

5
È possibile utilizzare os.path.joinsu ogni elemento di text_files. Potrebbe essere qualcosa del genere text_files = [os.path.join(path, f) for f in os.listdir(path) if f.endswith('.txt')].
Seth

55

Puoi semplicemente usare pathlibs 1 :glob

import pathlib

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

o in un ciclo:

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

Se lo vuoi ricorsivo puoi usarlo .glob('**/*.txt)


1 Il pathlibmodulo è stato incluso nella libreria standard in Python 3.4. Ma puoi installare back-port di quel modulo anche su versioni precedenti di Python (cioè usando condao pip): pathlibe pathlib2.


**/*.txtnon è supportato dalle versioni precedenti di Python, quindi ho risolto questo problema con: foundfiles= subprocess.check_output("ls **/*.txt", shell=True) for foundfile in foundfiles.splitlines(): print foundfile
Roman,

1
@Roman Sì, era solo una vetrina di cosa si pathlibpotesse fare e ho già incluso i requisiti della versione di Python. :) Ma se il tuo approccio non è già stato pubblicato, perché non aggiungerlo come un'altra risposta?
MSeifert,

1
sì, pubblicare una risposta mi avrebbe dato sicuramente migliori possibilità di formattazione. Lo postero perché penso che questo sia un posto più appropriato per questo.
Roman,

5
Si noti che è possibile utilizzare anche rglobse si desidera cercare elementi in modo ricorsivo. Ad esempio.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')]

29

Mi piace 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)

O con generatori:

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)

28

Ecco altre versioni della stessa che producono risultati leggermente diversi:

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

3
Per i curiosi, glob1()è una funzione di supporto nel globmodulo che non è elencata nella documentazione di Python. Ci sono alcuni commenti incorporati che descrivono cosa fa nel file sorgente, vedi .../Lib/glob.py.
martineau,

1
@martineau: glob.glob1()non è pubblico ma è disponibile su Python 2.4-2.7; 3.0-3.2; PyPy; jython github.com/zed/test_glob1
jfs

1
Grazie, queste sono buone informazioni aggiuntive da avere quando si decide se utilizzare una funzione privata non documentata in un modulo. ;-) Ecco un po 'di più. La versione Python 2.7 è lunga solo 12 righe e sembra che possa essere facilmente estratta dal globmodulo.
martineau,

21

path.py è un'altra alternativa: 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

Fantastico, accetta anche espressioni regolari nel modello. Sto usando for f in p.walk(pattern='*.txt')ogni sottocartella
Kostanos,

1
Ya c'è anche pathlib. Puoi fare qualcosa del tipo: list(p.glob('**/*.py'))
user2233949

15

Python v3.5 +

Metodo rapido utilizzando os.scandir in una funzione ricorsiva. Cerca tutti i file con un'estensione specificata nella cartella e nelle sottocartelle.

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)

Aggiornamento aprile 2019

Se si cercano directory che contengono 10.000 file, l'aggiunta a un elenco diventa inefficiente. "Produrre" i risultati è una soluzione migliore. Ho anche incluso una funzione per convertire l'output in un Dataframe Pandas.

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)

14

Python ha tutti gli strumenti per farlo:

import os

the_dir = 'the_dir_that_want_to_search_in'
all_txt_files = filter(lambda x: x.endswith('.txt'), os.listdir(the_dir))

1
Se vuoi che all_txt_files sia un elenco:all_txt_files = list(filter(lambda x: x.endswith('.txt'), os.listdir(the_dir)))
Ena,

12

Per ottenere tutti i nomi di file '.txt' all'interno della cartella 'dataPath' come un elenco in modo Pythonic:

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

12

Prova questo, troverai tutti i tuoi file in modo ricorsivo:

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)

non con la versione ricorsiva (doppia stella:) **. Disponibile solo in Python 3. Quello che non mi piace è la chdirparte. Non ce n'è bisogno.
Jean-François Fabre

2
bene, potresti usare la libreria os per unire il percorso, ad esempio, filepath = os.path.join('wallpaper')e poi usarlo come glob.glob(filepath+"**/*.psd", recursive = True), che produrrebbe lo stesso risultato.
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

8

Ho fatto un test (Python 3.6.4, W7x64) per vedere quale soluzione è la più veloce per una cartella, senza sottodirectory, per ottenere un elenco di percorsi di file completi per i file con un'estensione specifica.

Per farla breve, per questo compito os.listdir()è il più veloce ed è 1,7 volte più veloce del successivo migliore: os.walk()(con una pausa!), 2,7 volte più veloce pathlib, os.scandir()3,2 volte più veloce di e 3,3 volte più veloce di glob.
Tieni presente che tali risultati cambieranno quando avrai bisogno di risultati ricorsivi. Se si copia / incolla un metodo di seguito, aggiungere un .lower (), altrimenti .EXT non verrà trovato durante la ricerca di .ext.

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

risultati:

# Python 3.6.4
0.431
0.515
0.161
0.548
0.537
0.274

La documentazione di Python 3.6.5 afferma: La funzione os.scandir () restituisce le voci della directory insieme alle informazioni sugli attributi del file, fornendo prestazioni migliori [di os.listdir ()] per molti casi d'uso comuni.
Bill Oldroyd,

Mi manca l'estensione del ridimensionamento di questo test quanti file hai usato in questo test? come si confrontano se si scala il numero su / giù?
N4ppeL

5

Questo codice mi semplifica la vita.

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)


5

Per ottenere una matrice di nomi di file ".txt" da una cartella denominata "dati" nella stessa directory di solito utilizzo questa semplice riga di codice:

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

3

Ti suggerisco di usare fnmatch e il metodo superiore. In questo modo puoi trovare uno dei seguenti:

  1. Nome. testo ;
  2. Nome. testo ;
  3. Nome. Testo

.

import fnmatch
import os

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

3

Eccone uno con extend()

types = ('*.jpg', '*.png')
images_list = []
for files in types:
    images_list.extend(glob.glob(os.path.join(path, files)))

Da non usare con .txt:)
Efreeto,

2

Soluzione funzionale con sottodirectory:

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

15
Questo codice vorresti mantenere a lungo termine?
Simeon Visser,

2

Nel caso in cui la cartella contenga molti file o la memoria sia un vincolo, considerare l'utilizzo di generatori:

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

Opzione A: Iterate

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

Opzione B: ottieni tutto

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

2

Una soluzione copia-pastable simile a quella di 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

1

utilizzare il modulo del sistema operativo Python per trovare file con estensione specifica.

il semplice esempio è qui:

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

0

Molti utenti hanno risposto con le os.walkrisposte, che includono tutti i file ma anche tutte le directory e le sottodirectory e i loro file.

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)

O per uno in cui non hai bisogno di un generatore:

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)

Se utilizzerai le corrispondenze per qualcos'altro, potresti voler renderlo un elenco anziché un'espressione del generatore:

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

0

Un metodo semplice usando 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")

Anche se questo può essere reso più generalizzato.


modo molto poco sincero di controllare un'estensione. Anche non sicuro. E se il nome fosse troppo breve? e perché usare un elenco di caratteri e non stringhe?
Jean-François Fabre
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.