Encontre todos os arquivos em um diretório com extensão .txt em Python

1043

Como posso encontrar todos os arquivos em um diretório com a extensão .txtem python?

usertest
fonte

Respostas:

2358

Você pode usar glob:

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

ou simplesmente os.listdir:

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

ou se você quiser atravessar o diretório, 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
fonte
11
Usando a solução 2, como você criaria um arquivo ou uma lista com essas informações?
Merlin
72
@ ghostdog74: Na minha opinião, seria mais apropriado escrever do for file in fque para, for files in fuma vez que o que está na variável é um único nome de arquivo. Melhor ainda seria mudar os fto filese então os loops for poderiam se tornar for file in files.
26610 martineau
45
@computermacgyver: Não, filenão é uma palavra reservada, apenas o nome de uma função predefinida, por isso é bem possível usá-la como um nome de variável em seu próprio código. Embora seja verdade que geralmente se deve evitar colisões como essa, fileé um caso especial, porque quase nunca há necessidade de usá-lo, por isso é frequentemente considerado uma exceção à diretriz. Se você não quiser fazer isso, o PEP8 recomenda anexar um único sublinhado a esses nomes, ou seja file_, o que você teria que concordar que ainda é bastante legível.
martineau
9
Obrigado, Martineau, você está absolutamente certo. Eu pulei rápido demais para conclusões.
computermacgyver
40
Uma maneira mais pitônica de # 2 pode ser para arquivo em [f para f em os.listdir ('/ mydir') se f.endswith ('. Txt')]:
ozgur
247

Use glob .

>>> import glob
>>> glob.glob('./*.txt')
['./outline.txt', './pip-log.txt', './test.txt', './testingvim.txt']
Muhammad Alkarouri
fonte
Isso não só é fácil, como também não diferencia maiúsculas de minúsculas. (Pelo menos, é no Windows, como deveria ser Eu não tenho certeza sobre outros sistemas operacionais..)
Jon Coombs
35
Cuidado globpara não encontrar arquivos recursivamente se o seu python estiver abaixo de 3,5. mais informada
qun
a melhor parte é que você pode usar teste de expressão regular * .txt
Alex Punnen
@JonCoombs nope. Pelo menos não no Linux.
Karuhanga
157

Algo assim deve fazer o trabalho

for root, dirs, files in os.walk(directory):
    for file in files:
        if file.endswith('.txt'):
            print file
Adam Byrtek
fonte
73
+1 para nomear suas variáveis ​​em root, dirs, filesvez de r, d, f. Muito mais legível.
Clément
27
Observe que isso faz distinção entre maiúsculas e minúsculas (não corresponde a .TXT ou .Txt), portanto você provavelmente desejará fazer file.lower (). Endswith ('. Txt'):
Jon Coombs
1
sua resposta lida com o subdiretório.
Sam Liao
117

Algo assim vai 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
fonte
Como eu salvaria o caminho nos arquivos de texto? ['path / euc-cn.txt', ... 'path / windows-950.txt']]
IceQueeny 7/11
5
Você poderia usar os.path.joinem cada elemento de text_files. Pode ser algo parecido text_files = [os.path.join(path, f) for f in os.listdir(path) if f.endswith('.txt')].
Seth
55

Você pode simplesmente usar pathlibs 1 :glob

import pathlib

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

ou em um loop:

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

Se você quiser recursivo, você pode usar .glob('**/*.txt)


1 O pathlibmódulo foi incluído na biblioteca padrão no python 3.4. Mas você pode instalar portas traseiras desse módulo, mesmo em versões mais antigas do Python (ou seja, usando condaor pip): pathlibe pathlib2.

MSeifert
fonte
**/*.txtnão é suportado pelo python mais velho versions.So Eu resolvi isso com: foundfiles= subprocess.check_output("ls **/*.txt", shell=True) for foundfile in foundfiles.splitlines(): print foundfile
Roman
1
@ Roman Sim, era apenas uma demonstração do que pathlibposso fazer e eu já incluí os requisitos de versão do Python. :) Mas se sua abordagem ainda não foi publicada, por que não adicioná-la como outra resposta?
MSeifert
1
sim, postar uma resposta me daria melhores possibilidades de formatação, definitivamente. Postei porque acho que esse é um lugar mais apropriado.
Roman
5
Observe que você também pode usar rglobse desejar procurar itens recursivamente. Por exemplo.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
fonte
29

Eu gosto do 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)

Ou com geradores:

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

Aqui estão mais versões do mesmo que produzem resultados ligeiramente 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
fonte
3
Para os curiosos, glob1()é uma função auxiliar no globmódulo que não está listada na documentação do Python. Existem alguns comentários embutidos descrevendo o que ele faz no arquivo de origem, consulte .../Lib/glob.py.
26610 martineau
1
@martineau: glob.glob1()não é público, mas está disponível no Python 2.4-2.7; 3.0-3.2; pypy; jython github.com/zed/test_glob1
jfs
1
Obrigado, essas são boas informações adicionais quando você decide se deseja usar uma função privada não documentada em um módulo. ;-) Aqui está um pouco mais. A versão Python 2.7 tem apenas 12 linhas e parece que pode ser extraída facilmente do globmódulo.
martineau
21

path.py é outra 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
fonte
Legal, também aceita expressão regular em padrão. Estou usando for f in p.walk(pattern='*.txt')passar por cada subpastas
Kostanos
1
Ya também há pathlib. Você pode fazer algo como: list(p.glob('**/*.py'))
user2233949
15

Python v3.5 +

Método rápido usando os.scandir em uma função recursiva. Pesquisa todos os arquivos com uma extensão especificada na pasta e nas subpastas.

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)

Atualização em abril de 2019

Se você estiver pesquisando em diretórios que contêm arquivos de 10.000, anexar a uma lista se tornará ineficiente. 'Produzir' os resultados é uma solução melhor. Também incluí uma função para converter a saída em um Dataframe do 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
fonte
14

Python tem todas as ferramentas para fazer isso:

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
fonte
1
Se você deseja que all_txt_files seja uma lista:all_txt_files = list(filter(lambda x: x.endswith('.txt'), os.listdir(the_dir)))
Ena
12

Para obter todos os nomes de arquivos '.txt' dentro da pasta 'dataPath' como uma lista de maneira 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
ewalel
fonte
12

Tente isso, ele encontrará todos os seus arquivos recursivamente:

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
fonte
não com versão recursiva (estrela dupla :) **. Disponível apenas em python 3. O que eu não gosto é a chdirparte. Não é preciso isso.
Jean-François Fabre
2
bem, você pode usar a biblioteca os para se juntar ao caminho, por exemplo, filepath = os.path.join('wallpaper')e depois usá-lo como glob.glob(filepath+"**/*.psd", recursive = True), o que produziria o mesmo 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
fonte
8

Fiz um teste (Python 3.6.4, W7x64) para ver qual solução é a mais rápida para uma pasta, sem subdiretórios, para obter uma lista dos caminhos completos dos arquivos com uma extensão específica.

Para resumir, essa tarefa os.listdir()é a mais rápida e é 1,7x mais rápida que a seguinte: os.walk()(com uma folga!), 2,7x mais rápida que pathlib, 3,2x mais rápida os.scandir()e 3,3x mais rápida glob.
Lembre-se de que esses resultados serão alterados quando você precisar de resultados recursivos. Se você copiar / colar um método abaixo, adicione um .lower (), caso contrário .EXT não seria encontrado ao pesquisar .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
user136036
fonte
A documentação do Python 3.6.5 declara: A função os.scandir () retorna entradas de diretório junto com informações de atributos de arquivo, oferecendo melhor desempenho [que os.listdir ()] para muitos casos de uso comuns.
Bill Oldroyd
Faltam a extensão de escala deste teste. Quantos arquivos você usou neste teste? como eles se comparam se você aumentar / diminuir o número?
N4ppeL 11/11/19
5

Este código torna minha vida mais simples.

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

Para obter uma matriz de nomes de arquivo ".txt" de uma pasta chamada "data" no mesmo diretório, costumo usar esta simples linha de código:

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

Eu sugiro que você use fnmatch e o método superior. Dessa forma, você pode encontrar um dos seguintes:

  1. Nome. txt ;
  2. Nome. TXT ;
  3. Nome. TXT

.

import fnmatch
import os

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

Aqui está um com extend()

types = ('*.jpg', '*.png')
images_list = []
for files in types:
    images_list.extend(glob.glob(os.path.join(path, files)))
Efreeto
fonte
Não para uso com .txt:)
Efreeto
2

Solução funcional com subdiretórios:

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
fonte
15
Esse código você deseja manter a longo prazo?
Simeon Visser
2

Caso a pasta contenha muitos arquivos ou a memória seja uma restrição, considere o uso de geradores:

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

Opção A: Iterar

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

Opção B: obter todos

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

Uma solução para copiar e colar, semelhante à do 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
fonte
1

use o módulo Python OS para encontrar arquivos com extensão específica.

o exemplo simples está aqui:

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

Muitos usuários responderam com os.walkrespostas, que incluem todos os arquivos, mas também todos os diretórios e subdiretórios e seus arquivos.

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)

Ou para um caso em que você não precisa de um gerador:

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 você vai usar correspondências para outra coisa, convém fazer uma lista em vez de uma expressão geradora:

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

Um método simples 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")

Embora isso possa ser mais generalizado.

BoRRis
fonte
maneira muito sintética de verificar uma extensão. Inseguro também. E se o nome for muito curto? e por que usar uma lista de caracteres e não seqüências de caracteres?
Jean-François Fabre