Encuentra todos los archivos en un directorio con extensión .txt en Python

Respuestas:

2359

Puedes usar glob:

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

o simplemente os.listdir:

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

o si desea recorrer el directorio, use 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
fuente
11
Usando la solución # 2, ¿cómo crearía un archivo o una lista con esa información?
Merlín
72
@ ghostdog74: En mi opinión, sería más apropiado escribir for file in fque para for files in fya que lo que está en la variable es un solo nombre de archivo. Aún mejor sería cambiar el fa filesy luego los bucles for podrían convertirse for file in files.
Martineau
46
@computermacgyver: No, fileno es una palabra reservada, solo el nombre de una función predefinida, por lo que es muy posible usarla como un nombre de variable en su propio código. Aunque es cierto que generalmente uno debe evitar colisiones como esa, filees un caso especial porque casi nunca hay necesidad de usarlo, por lo que a menudo se considera una excepción a la guía. Si no desea hacer eso, PEP8 recomienda agregar un solo guión bajo a dichos nombres, es decir file_, lo que debe aceptar es bastante legible.
Martineau
99
Gracias, Martineau, tienes toda la razón. Salté demasiado rápido a las conclusiones.
computermacgyver
40
Una forma más pitónica para # 2 puede ser para el archivo en [f para f en os.listdir ('/ mydir') si f.endswith ('. Txt')]:
ozgur
247

Usa glob .

>>> import glob
>>> glob.glob('./*.txt')
['./outline.txt', './pip-log.txt', './test.txt', './testingvim.txt']
Muhammad Alkarouri
fuente
Esto no solo es fácil, también es insensible a mayúsculas y minúsculas. (Al menos, está en Windows, como debería ser. No estoy seguro acerca de otros sistemas operativos.)
Jon Coombs
35
Tenga en cuenta que globno puede encontrar archivos de forma recursiva si su python es inferior a 3.5. más informar
qun
la mejor parte es que puedes usar la prueba de expresión regular * .txt
Alex Punnen
@JonCoombs no. Al menos no en Linux.
Karuhanga
157

Algo así debería hacer el trabajo

for root, dirs, files in os.walk(directory):
    for file in files:
        if file.endswith('.txt'):
            print file
Adam Byrtek
fuente
73
+1 para nombrar sus variables en root, dirs, fileslugar de r, d, f. Mucho más legible.
Clément
27
Tenga en cuenta que esto distingue entre mayúsculas y minúsculas (no coincidirá con .TXT o .Txt), por lo que probablemente querrá hacerlo si file.lower (). Termina con ('. Txt'):
Jon Coombs
1
su respuesta trata con el subdirectorio.
Sam Liao
117

Algo como esto funcionará:

>>> 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
fuente
¿Cómo guardaría la ruta a los archivos de texto? ['path / euc-cn.txt', ... 'path / windows-950.txt']
IceQueeny
55
Podrías usar os.path.joinen cada elemento de text_files. Podría ser algo así text_files = [os.path.join(path, f) for f in os.listdir(path) if f.endswith('.txt')].
Seth
55

Simplemente puede usar pathlibs 1 :glob

import pathlib

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

o en un bucle:

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

Si lo quieres recursivo puedes usar .glob('**/*.txt)


1 El pathlibmódulo se incluyó en la biblioteca estándar en Python 3.4. Pero puede instalar puertos posteriores de ese módulo incluso en versiones anteriores de Python (es decir, usando condao pip): pathliby pathlib2.

MSeifert
fuente
**/*.txtno es compatible con versiones anteriores de Python, así que resolví esto con: foundfiles= subprocess.check_output("ls **/*.txt", shell=True) for foundfile in foundfiles.splitlines(): print foundfile
Roman
1
@Roman Sí, fue solo una muestra de lo que pathlibpuede hacer y ya incluí los requisitos de la versión de Python. :) Pero si su enfoque no se ha publicado ya, ¿por qué no agregarlo como otra respuesta?
MSeifert
1
sí, publicar una respuesta me hubiera dado mejores posibilidades de formato, definitivamente. Lo publico allí porque creo que este es un lugar más apropiado para él.
Romano
55
Tenga en cuenta que también puede usar rglobsi desea buscar elementos de forma recursiva. Por ejemplo.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')]
usuario3281344
fuente
29

Me gusta 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 generadores:

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

Aquí hay más versiones de la misma que producen resultados ligeramente diferentes:

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
fuente
3
Para los curiosos, glob1()es una función auxiliar en el globmódulo que no figura en la documentación de Python. Hay algunos comentarios en línea que describen lo que hace en el archivo fuente, vea .../Lib/glob.py.
Martineau
1
@martineau: glob.glob1()no es público pero está disponible en Python 2.4-2.7; 3.0-3.2; pypy jython github.com/zed/test_glob1
jfs
1
Gracias, esa es una buena información adicional para decidir cuándo usar una función privada no documentada en un módulo. ;-) Aquí hay un poco más. La versión Python 2.7 tiene solo 12 líneas y parece que podría extraerse fácilmente del globmódulo.
Martineau
21

path.py es otra 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
Anuvrat Parashar
fuente
Genial, acepta también expresiones regulares en el patrón. Estoy usando for f in p.walk(pattern='*.txt')ir a través de todas las subcarpetas
Kostanos
1
Ya también hay pathlib. Puede hacer algo como: list(p.glob('**/*.py'))
user2233949
15

Python v3.5 +

Método rápido usando os.scandir en una función recursiva. Busca todos los archivos con una extensión específica en la carpeta y subcarpetas.

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)

Actualización de abril de 2019

Si está buscando en directorios que contienen archivos de 10.000, agregar a una lista se vuelve ineficiente. 'Ceder' los resultados es una mejor solución. También he incluido una función para convertir la salida a un marco de datos de 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)
DougR
fuente
14

Python tiene todas las herramientas para hacer esto:

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
fuente
1
Si desea que all_txt_files sea una lista:all_txt_files = list(filter(lambda x: x.endswith('.txt'), os.listdir(the_dir)))
Ena
12

Para obtener todos los nombres de archivo '.txt' dentro de la carpeta 'dataPath' como una lista de manera pitónica:

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

Intente esto, encontrará todos sus archivos de forma recursiva:

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
fuente
no con versión recursiva (doble estrella:) **. Solo disponible en python 3. Lo que no me gusta es la chdirpieza. No hay necesidad de eso.
Jean-François Fabre
2
bueno, podría usar la biblioteca os para unir la ruta, por ejemplo, filepath = os.path.join('wallpaper')y luego usarla como glob.glob(filepath+"**/*.psd", recursive = True), lo que produciría el mismo resultado.
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
fuente
8

Hice una prueba (Python 3.6.4, W7x64) para ver qué solución es la más rápida para una carpeta, sin subdirectorios, para obtener una lista de rutas de archivos completas para archivos con una extensión específica.

Para abreviar, esta tarea os.listdir()es la más rápida y es 1.7 veces más rápida que la siguiente mejor: os.walk()(¡con un descanso!), 2.7 veces más rápida pathlib, 3.2 veces más rápida os.scandir()y 3.3 veces más rápida que glob.
Tenga en cuenta que esos resultados cambiarán cuando necesite resultados recursivos. Si copia / pega un método a continuación, agregue un .lower () de lo contrario, no se encontrará .EXT al buscar .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))

Resultados:

# Python 3.6.4
0.431
0.515
0.161
0.548
0.537
0.274
usuario136036
fuente
La documentación de Python 3.6.5 establece: la función os.scandir () devuelve entradas de directorio junto con información de atributos de archivo, lo que proporciona un mejor rendimiento [que os.listdir ()] para muchos casos de uso comunes.
Bill Oldroyd
Me falta el alcance de escala de esta prueba ¿Cuántos archivos usaste en esta prueba? ¿Cómo se comparan si escalas el número arriba / abajo?
N4ppeL
5

Este código hace que mi vida sea más simple.

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

Para obtener una matriz de nombres de archivo ".txt" de una carpeta llamada "datos" en el mismo directorio, generalmente uso esta simple línea de código:

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

Le sugiero que use fnmatch y el método superior. De esta manera puede encontrar cualquiera de los siguientes:

  1. Nombre. TXT ;
  2. Nombre. TXT ;
  3. Nombre. TXT

.

import fnmatch
import os

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

Aquí hay uno con extend()

types = ('*.jpg', '*.png')
images_list = []
for files in types:
    images_list.extend(glob.glob(os.path.join(path, files)))
Efreeto
fuente
No es para usar con .txt:)
Efreeto
2

Solución funcional con subdirectorios:

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
fuente
15
¿Este código te gustaría mantener a largo plazo?
Simeon Visser
2

En caso de que la carpeta contenga muchos archivos o la memoria sea una restricción, considere usar generadores:

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

Opción A: iterar

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

Opción B: obtener todo

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

Una solución copiable y similar a la de 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
fuente
1

use el módulo Python OS para buscar archivos con extensión específica.

El ejemplo simple está aquí:

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

Muchos usuarios han respondido con os.walkrespuestas, que incluyen todos los archivos pero también todos los directorios y subdirectorios y sus archivos.

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 para uno que no necesita un generador:

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)

Si va a utilizar coincidencias para otra cosa, es posible que desee que sea una lista en lugar de una expresión generadora:

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

Un método simple mediante el uso de forbucle:

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

Aunque esto se puede hacer más generalizado.

BoRRis
fuente
Una forma muy poco fónica de verificar una extensión. Inseguro también. ¿Qué pasa si el nombre es demasiado corto? ¿Y por qué usar una lista de caracteres y no cadenas?
Jean-François Fabre