Como faço para listar todos os arquivos de um diretório?

3473

Como posso listar todos os arquivos de um diretório no Python e adicioná-los a um list?

duhhunjonn
fonte

Respostas:

4215

os.listdir()você terá tudo o que está em um diretório - arquivos e diretórios .

Se você quiser apenas arquivos, poderá filtrar isso usando os.path:

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

ou você pode usar o os.walk()que produzirá duas listas para cada diretório visitado - dividindo-se em arquivos e diretórios para você. Se você deseja apenas o diretório superior, basta interromper a primeira vez que ele produzir

from os import walk

f = []
for (dirpath, dirnames, filenames) in walk(mypath):
    f.extend(filenames)
    break
pycruft
fonte
87
Um pouco mais simples: (_, _, filenames) = walk(mypath).next() (se você está confiante de que a caminhada irá retornar pelo menos um valor, que deveria.)
misterbee
9
Pequena modificação para armazenar caminhos completos: para (caminho de caminho, nomes de arquivos, nomes de arquivos) no os.walk (caminho do meu): checksum_files.extend (os.path.join (caminho do arquivo, nome do arquivo) para o nome do arquivo nos nomes de arquivos) break
okigan
150
f.extend(filenames)não é realmente equivalente a f = f + filenames. extendserá modificado fno local, enquanto a adição cria uma nova lista em um novo local de memória. Isso significa que extendgeralmente é mais eficiente que +, mas às vezes pode causar confusão se vários objetos mantiverem referências à lista. Por fim, vale a pena notar que isso f += filenamesé equivalente a f.extend(filenames), não f = f + filenames .
Benjamin Hodgson
30
@misterbee, sua solução é a melhor, apenas uma pequena melhoria:_, _, filenames = next(walk(mypath), (None, None, []))
bgusach
35
no uso do python 3.x(_, _, filenames) = next(os.walk(mypath))
ET-CS
1683

Eu prefiro usar o globmódulo, pois combina correspondência e expansão de padrões.

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

Ele retornará uma lista com os arquivos consultados:

['/home/adam/file1.txt', '/home/adam/file2.txt', .... ]
adamk
fonte
17
que é um atalho para listDir + fnmatch docs.python.org/library/fnmatch.html#fnmatch.fnmatch
Stefano
31
para esclarecer, isso não retorna o "caminho completo"; simplesmente retorna a expansão da glob, seja ela qual for. Por exemplo, dado que /home/user/foo/bar/hello.txt, se estiver sendo executado no diretório foo, o valor glob("bar/*.txt")retornará bar/hello.txt. Há casos em que você realmente deseja o caminho completo (ou seja, absoluto); para esses casos, consulte stackoverflow.com/questions/51520/…
michael
1
Relacionados: encontrar arquivos recursivamente com glob: stackoverflow.com/a/2186565/4561887
Gabriel Staples
6
não responde a essa pergunta. glob.glob("*")seria.
Jean-François Fabre
bonita!!!! então .... x=glob.glob("../train/*.png")me dará uma matriz dos meus caminhos, desde que eu saiba o nome da pasta. Tão legal!
Jennifer Crosby
859

Obtenha uma lista de arquivos com Python 2 e 3


os.listdir()

Como obter todos os arquivos (e diretórios) no diretório atual (Python 3)

A seguir, são métodos simples para recuperar apenas arquivos no diretório atual, usando os e a listdir()função, no Python 3. Explorações adicionais demonstrarão como retornar pastas no diretório, mas você não terá o arquivo no subdiretório, para o qual você pode usar o walk - discutido mais tarde).

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

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

glob

Achei a glob mais fácil de selecionar o arquivo do mesmo tipo ou com algo em comum. Veja o seguinte exemplo:

import glob

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

glob com compreensão de lista

import glob

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

glob com uma função

A função retorna uma lista da extensão fornecida (.txt, .docx ecc.) No argumento

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 estendendo o código anterior

A função agora retorna uma lista de arquivos que correspondem à string que você passa como argumento

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

resultado

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

Obter o nome completo do caminho com os.path.abspath

Como você notou, você não tem o caminho completo do arquivo no código acima. Se você precisar ter o caminho absoluto, poderá usar outra função do os.pathmódulo chamada _getfullpathname, colocando o arquivo que obtém os.listdir()como argumento. Existem outras maneiras de ter o caminho completo, como verificaremos mais tarde (substituí, como sugerido por mexmex, _getfullpathname with 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']

Obtenha o nome completo do caminho de um tipo de arquivo em todos os subdiretórios com walk

Acho isso muito útil para encontrar coisas em muitos diretórios e me ajudou a encontrar um arquivo sobre o qual não me lembrava do nome:

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(): obtém arquivos no diretório atual (Python 2)

No Python 2, se você quiser a lista dos arquivos no diretório atual, precisará fornecer o argumento como '.' ou os.getcwd () no método os.listdir.

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

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

Para subir na árvore de diretórios

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

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

Obter arquivos: os.listdir()em um diretório específico (Python 2 e 3)

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

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

Obter arquivos de um subdiretório específico com os.listdir()

import os

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

os.walk('.') - diretório atual

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

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

next(os.walk('.')) e 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:\\') - obtenha o caminho completo - compreensão da lista

 [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 - obtém o caminho completo - todos os arquivos em subdiretórios **

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() - obtenha apenas arquivos txt

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

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

Usando globpara obter o caminho completo dos arquivos

Se eu precisar do caminho absoluto dos arquivos:

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

Usando os.path.isfilepara evitar diretórios na lista

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

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

Com list comprehension:

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

Como alternativa, use em pathlib.Path()vez depathlib.Path(".")

Use o método glob em pathlib.Path ()

import pathlib

py = pathlib.Path().glob("*.py")
for file in py:
    print(file)

>>> stack_overflow_list.py
>>> stack_overflow_list_tkinter.py

Obtenha todos e apenas arquivos com 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']

Obtenha apenas arquivos com o próximo e entre em um diretório

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

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

Obtenha apenas diretórios com o próximo e entre em um diretório

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

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

Obtenha todos os nomes dos subdiretórios com 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() do Python 3.5 e superior

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

Exemplos:

Ex. 1: Quantos arquivos existem nos subdiretórios?

Neste exemplo, procuramos o número de arquivos incluídos em todo o diretório e seus subdiretórios.

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'

Ex.2: Como copiar todos os arquivos de um diretório para outro?

Um script para fazer o pedido em seu computador, localizando todos os arquivos de um tipo (padrão: pptx) e copiando-os em uma nova pasta.

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: Como obter todos os arquivos em um arquivo txt

Caso você queira criar um arquivo txt com todos os nomes de arquivos:

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

Exemplo: txt com todos os arquivos de um disco rígido

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

Todo o arquivo de C: \ em um arquivo de texto

Esta é uma versão mais curta do código anterior. Mude a pasta onde começar a encontrar os arquivos, se precisar começar de outra posição. Esse código gera um arquivo de texto de 50 mb no meu computador com algo menos de 500.000 linhas com arquivos com o caminho completo.

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

Como gravar um arquivo com todos os caminhos em uma pasta de um tipo

Com esta função, você pode criar um arquivo txt que terá o nome de um tipo de arquivo que você procura (por exemplo, pngfile.txt) com todo o caminho completo de todos os arquivos desse tipo. Às vezes, pode ser útil, eu acho.

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

(Novo) Encontre todos os arquivos e abra-os com tkinter GUI

Eu só queria adicionar neste 2019 um pequeno aplicativo para procurar todos os arquivos em um diretório e poder abri-los clicando duas vezes no nome do arquivo na lista. insira a descrição da imagem aqui

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()
Giovanni G. PY
fonte
14
Esta é uma mistura de muitas respostas para perguntas não feitas aqui. Também pode valer a pena explicar quais são as advertências ou abordagens recomendadas. Não é melhor conhecer uma maneira versus 20 maneiras de fazer a mesma coisa, a menos que eu também saiba qual é mais apropriado usar quando.
cs95 27/01
Ok, o mais rápido possível Vou dar uma olhada na minha resposta e tentar torná-la mais limpa e com informações mais úteis sobre a diferença entre os métodos etc.
Giovanni G. PY
Você não deve determinar a extensão do arquivo verificando se o nome do arquivo contém uma substring. Isso pode causar muitos problemas. Eu recomendo sempre verificar se o nome do arquivo termina com a substring específica.
ni1ight 2/03
Ok, @ n1light eu mudei o código ...
Giovanni G. PY
812
import os
os.listdir("somedirectory")

retornará uma lista de todos os arquivos e diretórios no "somedirectory".

sepp2k
fonte
11
Isso retorna o caminho relativo dos arquivos, em comparação com o caminho completo retornado porglob.glob
xji 17/16
22
@ JIXiang: os.listdir()sempre retorna meros nomes de arquivos (não caminhos relativos). O glob.glob()retorno é conduzido pelo formato do caminho do padrão de entrada.
mklement0
os.listdir () -> Sempre lista o diretório e o arquivo dentro do local fornecido. Existe alguma maneira de listar apenas diretório e não arquivos?
Ronya
160

Uma solução de uma linha para obter apenas a lista de arquivos (sem subdiretórios):

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

ou caminhos absolutos:

paths = [os.path.join(path, fn) for fn in next(os.walk(path))[2]]
Remi
fonte
7
Apenas uma linha, se você já tiver import os. Parece menos conciso do que glob()para mim.
ArtOfWarfare 28/11
4
problema com glob é que uma pasta chamada 'something.something' seria devolvido por glob ( '/ home / adam /*.*')
Remi
6
No OS X, há algo chamado pacote. É um diretório que geralmente deve ser tratado como um arquivo (como um .tar). Você gostaria que aqueles tratados como um arquivo ou um diretório? Usar glob()o trataria como um arquivo. Seu método o trataria como um diretório.
ArtOfWarfare
132

Obtendo caminhos de arquivo completos de um diretório e de todos os seus subdiretórios

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

  • O caminho que forneci na função acima continha 3 arquivos - dois no diretório raiz e outro em uma subpasta chamada "SUBFOLDER". Agora você pode fazer coisas como:
  • print full_file_paths que imprimirá a lista:

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

Se desejar, você pode abrir e ler o conteúdo ou se concentrar apenas em arquivos com a extensão ".dat", como no código abaixo:

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

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

Johnny
fonte
Esta é a única resposta.
thelearner 13/04
78

Desde a versão 3.4, existem iteradores internos para isso, que são muito mais eficientes do que os.listdir():

pathlib: Novo na versão 3.4.

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

De acordo com o PEP 428 , o objetivo da pathlibbiblioteca é fornecer uma hierarquia simples de classes para manipular os caminhos do sistema de arquivos e as operações comuns que os usuários fazem sobre eles.

os.scandir(): Novo na versão 3.5.

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

Observe que os.walk()usa em os.scandir()vez da os.listdir()versão 3.5 e sua velocidade aumentou de 2 a 20 vezes, de acordo com o PEP 471 .

Deixe-me também recomendar a leitura do comentário de ShadowRanger abaixo.

SzieberthAdam
fonte
1
Obrigado! Eu acho que é a única solução que não retorna diretamente a list. Poderia usar em p.namevez do primeiro palternativamente, se preferir.
jeromej
1
Bem-vinda! Eu preferiria gerar pathlib.Path()instâncias, pois eles têm muitos métodos úteis que eu não gostaria de desperdiçar. Você também pode chamá str(p)-los para nomes de caminhos.
SzieberthAdam
6
Nota: A os.scandirsolução será mais eficiente do que os.listdircom uma os.path.is_fileverificação ou algo parecido, mesmo se você precisar de uma list(para que você não se beneficie da iteração lenta), porque os.scandirusa APIs fornecidas pelo SO que fornecem is_fileinformações gratuitamente enquanto itera , não por arquivo de ida e volta para o disco para stateles em tudo (no Windows, os DirEntrys te completa statinformações de graça, em sistemas * NIX ele precisa statde informações para além is_file, is_diretc., mas DirEntrycaches na primeira statpor conveniência).
ShadowRanger #
1
Você também pode usar entry.namepara obter apenas o nome do arquivo ou entry.pathpara obter o caminho completo. Não há mais os.path.join () em todo o lugar.
user136036
56

Notas preliminares

  • Embora exista uma clara diferenciação entre os termos de arquivo e diretório no texto da pergunta, alguns podem argumentar que os diretórios são realmente arquivos especiais
  • A declaração: " todos os arquivos de um diretório " podem ser interpretados de duas maneiras:
    1. Todos os descendentes diretos (ou nível 1) apenas
    2. Todos os descendentes em toda a árvore de diretórios (incluindo os subdiretórios)
  • Quando a pergunta foi feita, imagino que o Python 2 fosse a versão LTS , no entanto, os exemplos de código serão executados pelo Python 3 ( .5 ) (eu os manterei o mais compatível possível com o Python 2 ; também, qualquer código pertencente a O Python que vou postar é da v3.5.4 - a menos que seja especificado de outra forma). Isso tem consequências relacionadas a outra palavra-chave na pergunta: " adicione-as a uma lista ":

    • No pré- Python 2.2 versões , as sequências (iteráveis) eram representadas principalmente por listas (tuplas, conjuntos, ...)
    • No Python 2.2 , o conceito de gerador ( [Python.Wiki]: Generators ) - cortesia de [Python 3]: A declaração de rendimento ) - foi introduzido. Com o passar do tempo, as contrapartes do gerador começaram a aparecer para funções que retornavam / trabalhavam com listas
    • No Python 3 , gerador é o comportamento padrão
    • Não tenho certeza se o retorno de uma lista ainda é obrigatório (ou um gerador faria também), mas passar um gerador para o construtor da lista criará uma lista a partir dela (e também a consumirá). O exemplo abaixo ilustra as diferenças em [Python 3]: map ( function, iterable, ... )
    >>> 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'>)
  • Os exemplos serão baseados em um diretório chamado root_dir com a seguinte estrutura (este exemplo é para Win , mas também estou usando a mesma árvore no 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


Soluções

Abordagens programáticas:

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

    Retorne uma lista contendo os nomes das entradas no diretório fornecido pelo caminho. A lista está em ordem arbitrária e não inclui as entradas especiais '.'e '..'...


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

    Um exemplo mais elaborado ( 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()

    Notas :

    • Existem duas implementações:
      • Um que usa geradores (é claro que aqui parece inútil, pois eu imediatamente converto o resultado em uma lista)
      • O clássico (nomes de funções que terminam em _old )
    • A recursão é usada (para entrar nos subdiretórios)
    • Para cada implementação, existem duas funções:
      • Um que começa com um sublinhado ( _ ): "privado" (não deve ser chamado diretamente) - faz todo o trabalho
      • O público (wrapper sobre o anterior): apenas retira o caminho inicial (se necessário) das entradas retornadas. É uma implementação feia, mas é a única ideia que eu poderia ter neste momento
    • Em termos de desempenho, os geradores geralmente são um pouco mais rápidos (considerando a criação e a iteração tempos de ), mas eu não os testei em funções recursivas e também estou interagindo dentro da função por geradores internos - não sei como o desempenho amigável é isso
    • Brinque com os argumentos para obter resultados diferentes


    Saída :

    (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 ( caminho = '.' ) ( Python 3.5 +, backport: [PyPI]: scandir )

    Retorne um iterador de objetos os.DirEntry correspondentes às entradas no diretório fornecidas pelo caminho . As entradas são produzidas em ordem arbitrária e as entradas especiais '.'e '..'não estão incluídas.

    Usar scandir () em vez de listdir () pode aumentar significativamente o desempenho do código que também precisa de informações sobre o tipo ou o atributo do arquivo, porque os objetos os.DirEntry expõem essas informações se o sistema operacional as fornecer ao varrer um diretório. Todos os métodos os.DirEntry podem executar uma chamada do sistema, mas is_dir () e is_file () geralmente requerem apenas uma chamada do sistema para links simbólicos; os.DirEntry.stat () sempre requer uma chamada do sistema no Unix, mas apenas uma para links simbólicos no Windows.


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

    Notas :

    • É semelhante a os.listdir
    • Mas também é mais flexível (e oferece mais funcionalidades), mais Python ic (e, em alguns casos, mais rápido)


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

    Gere os nomes de arquivo em uma árvore de diretórios, percorrendo a árvore de cima para baixo ou de baixo para cima. Para cada diretório na árvore com raiz no diretório superior (incluindo top si), ele produz um 3-tupla ( 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', [], [])

    Notas :

    • Nos bastidores, ele usa os.scandir( os.listdirem versões mais antigas)
    • Faz o trabalho pesado recorrendo em subpastas


  1. [Python 3]: glob. glob ( nome do caminho, *, recursivo = Falso ) ( [Python 3]: glob. iglob ( nome do caminho, *, recursivo = Falso ) )

    Retorne uma lista possivelmente vazia de nomes de caminhos que correspondem ao nome do caminho , que deve ser uma sequência contendo uma especificação de caminho. o nome do caminho pode ser absoluto (curtir /usr/src/Python-1.5/Makefile) ou relativo (curtir ../../Tools/*/*.gif) e pode conter curingas no estilo de shell. Links simbólicos quebrados estão incluídos nos resultados (como no shell).
    ...
    Alterado na versão 3.5 : Suporte para globs recursivos usando “ **”.


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

    Notas :

    • Usos os.listdir
    • Para árvores grandes (especialmente se a recursiva estiver ativada ), é preferível o iglob
    • Permite filtragem avançada com base no nome (devido ao curinga)


  1. [Python 3]: classe pathlib. Caminho ( * pathegments ) ( 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']

    Notas :

    • Esta é uma maneira de alcançar nosso objetivo
    • É o estilo OOP de lidar com caminhos
    • Oferece muitas funcionalidades


  1. [Python 2]: dircache.listdir (caminho) ( somente 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) via [Python 3]: ctypes - Uma biblioteca de funções estrangeira para Python ( específico para POSIX )

    ctypes é uma biblioteca de funções estrangeira para Python. Ele fornece tipos de dados compatíveis com C e permite funções de chamada em DLLs ou bibliotecas compartilhadas. Ele pode ser usado para agrupar essas bibliotecas em Python puro.

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

    Notas :

    • Ele carrega as três funções da libc (carregadas no processo atual) e as chama (para obter mais detalhes, verifique [SO]: Como verifico se um arquivo existe sem exceções? (Resposta de @ CristiFati) - últimas notas do item # 4. ) Isso colocaria essa abordagem muito perto da borda do Python / C
    • LinuxDirent64 é a representação ctypes de struct dirent64 de [man7]: dirent.h (0P) (assim como o constantes DT_ ) da minha máquina: Ubtu 16 x64 ( 4.10.0-40-generic e libc6-dev: amd64 ). Em outros tipos / versões, a definição da estrutura pode ser diferente e, se for o caso, o alias do ctypes deve ser atualizado, caso contrário, resultará em Comportamento indefinido
    • Retorna dados no os.walkformato do. Eu não me incomodei em torná-lo recursivo, mas a partir do código existente, isso seria uma tarefa bastante trivial
    • Tudo é possível no Win também, os dados (bibliotecas, funções, estruturas, constantes, ...) diferem


    Saída :

    [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 ( específico para Win )

    Recupera uma lista de nomes de arquivos correspondentes, usando a API Unicode do Windows. Uma interface para as funções de fechamento da API FindFirstFileW / FindNextFileW / Find.


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

    Notas :


  1. Instale algum (outro) pacote de terceiros que faça o truque
    • Provavelmente, dependerá de um (ou mais) dos itens acima (talvez com pequenas personalizações)


Notas :

  • O código deve ser portátil (exceto locais direcionados a uma área específica - que estão marcadas) ou cruzado:

    • plataforma ( Nix , Win ,)
    • PitãoVersão (2, 3,)
  • Vários estilos de caminho (absoluto, parentes) foram usados ​​nas variantes acima, para ilustrar o fato de que as "ferramentas" usadas são flexíveis nessa direção

  • os.listdire os.scandiruse opendir / readdir / closedir ( [MS.Docs]: função FindFirstFileW / [MS.Docs]: função FindNextFileW / [MS.Docs]: função FindClose ) (via [GitHub]: python / cpython - (master) cpython / Módulos / posixmodule.c )

  • win32file.FindFilesWtambém usa essas funções ( específicas do Win ) (via [GitHub]: mhammond / pywin32 - (mestre) pywin32 / win32 / src / win32file.i )

  • _get_dir_content (do ponto 1 ) pode ser implementado usando qualquer uma dessas abordagens (algumas exigirão mais trabalho e outras menos)

    • Alguma filtragem avançada (em vez de apenas arquivo x diretório) poderia ser feita: por exemplo, o argumento include_folders poderia ser substituído por outro (por exemplo, filter_func ), que seria uma função que seguiria o caminho como argumento: filter_func=lambda x: True(isso não desaparece qualquer coisa) e dentro de _get_dir_content algo como: if not filter_func(entry_with_path): continue(se a função falhar em uma entrada, ela será ignorada), mas quanto mais complexo o código se tornar, mais tempo será necessário para executar
  • Nota bene! Como a recursão é usada, devo mencionar que fiz alguns testes no meu laptop ( Win 10 x64 ), totalmente não relacionados a esse problema, e quando o nível de recursão estava atingindo valores em algum lugar na faixa ( 990 .. 1000) ( recursionlimit - 1000 (padrão)), recebi o StackOverflow :). Se a árvore de diretórios exceder esse limite (não sou especialista em FS , não sei se isso é possível), isso pode ser um problema.
    Devo também mencionar que não tentei aumentar o limite de recursão porque não tenho experiência na área (quanto posso aumentá-lo antes de aumentar também a pilha no SOnível), mas em teoria sempre haverá a possibilidade de falha, se a profundidade do diretório for maior que o limite de recursão mais alto possível (nessa máquina)

  • As amostras de código são apenas para fins demonstrativos. Isso significa que eu não levei em consideração o tratamento de erros (acho que não há nenhum bloco try / except / else / finalmente ), portanto o código não é robusto (o motivo é: mantê-lo o mais simples e curto possível ) Para a produção , o tratamento de erros também deve ser adicionado

Outras abordagens:

  1. Use Python apenas como um wrapper

    • Tudo é feito usando outra tecnologia
    • Essa tecnologia é invocada no Python
    • O sabor mais famoso que conheço é o que chamo de abordagem de administrador do sistema :

      • Use Python (ou qualquer outra linguagem de programação) para executar comandos do shell (e analisar suas saídas)
      • Alguns consideram isso um hack puro
      • Eu considero isso mais como uma solução alternativa esfarrapada ( gainarie ), pois a ação em si é executada a partir do shell ( cmd neste caso) e, portanto, não tem nada a ver com Python .
      • A filtragem ( grep/ findstr) ou a formatação de saída pode ser feita nos dois lados, mas não vou insistir nisso. Além disso, eu usei deliberadamente em os.systemvez de 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

    Em geral, essa abordagem deve ser evitada, pois se algum formato de saída de comando diferir ligeiramente entre versões / tipos de SO , o código de análise também deverá ser adaptado; para não mencionar diferenças entre localidades).

CristiFati
fonte
48

Gostei muito da resposta de adamk , sugerindo que você use glob(), do módulo com o mesmo nome. Isso permite que você tenha correspondência de padrões com *s.

Mas, como outras pessoas apontaram nos comentários, glob()podem ser enganados por direções inconsistentes de barras. Para ajudar nisso, sugiro que você use as funções join()e expanduser()no os.pathmódulo, e talvez a getcwd()função no osmódulo também.

Como exemplos:

from glob import glob

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

O que foi dito acima é terrível - o caminho foi codificado e só funcionará no Windows entre o nome da unidade e os \códigos codificados no caminho.

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

O exemplo acima funciona melhor, mas depende do nome da pasta, Usersque geralmente é encontrada no Windows e não é encontrada em outros sistemas operacionais. Também depende do usuário ter um nome específico 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'))

Isso funciona perfeitamente em todas as plataformas.

Outro ótimo exemplo que funciona perfeitamente entre plataformas e faz algo um pouco diferente:

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

Espero que esses exemplos o ajudem a ver o poder de algumas das funções que você pode encontrar nos módulos padrão da biblioteca Python.

ArtOfWarfare
fonte
4
Diversão extra: a partir do Python 3.5, **funciona enquanto você definir recursive = True. Veja os documentos aqui: 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 
Apogentus
fonte
obrigado! trabalho! perfeito!
ambigus9
23

Se você está procurando uma implementação Python de find , esta é uma receita que eu uso com bastante frequência:

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

Então criei um pacote PyPI e também há um repositório GitHub . Espero que alguém ache isso potencialmente útil para esse código.

Yauhen Yakimovich
fonte
14

Para obter melhores resultados, você pode usar o listdir()métodoos módulo junto com um gerador (um gerador é um iterador poderoso que mantém seu estado, lembra?). O código a seguir funciona bem com as duas versões: Python 2 e Python 3.

Aqui está um código:

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)

O listdir()método retorna a lista de entradas para o diretório especificado. O método os.path.isfile()retornará Truese a entrada fornecida for um arquivo. E o yieldoperador sai da função, mas mantém seu estado atual e retorna apenas o nome da entrada detectada como um arquivo. Todos os itens acima nos permitem fazer um loop sobre a função do gerador.

Andy
fonte
11

O retorno de uma lista de caminhos de arquivo absolutos não recursa em subdiretórios

L = [os.path.join(os.getcwd(),f) for f in os.listdir('.') if os.path.isfile(os.path.join(os.getcwd(),f))]
The2ndSon
fonte
2
Nota: os.path.abspath(f)seria um substituto um pouco mais barato os.path.join(os.getcwd(),f).
ShadowRanger
Eu seria mais eficiente ainda se você começasse cwd = os.path.abspath('.')e depois usasse em cwdvez de '.'e os.getcwd()para evitar cargas de chamadas de sistema redundantes.
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

Aqui eu uso uma estrutura recursiva.

pah8J
fonte
O mesmo pode ser alcançado em apenas uma linha com pathlib:filter(Path.is_file, Path().rglob('*'))
Georgy
9

Um professor sábio me disse uma vez que:

Quando existem várias maneiras estabelecidas de fazer algo, nenhuma delas é boa para todos os casos.

Assim, adicionarei uma solução para um subconjunto do problema: muitas vezes, queremos apenas verificar se um arquivo corresponde a uma sequência inicial e uma final, sem entrar em subdiretórios. Assim, gostaríamos de uma função que retorne uma lista de nomes de arquivos, como:

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

Se você deseja primeiro declarar duas funções, isso pode ser feito:

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

Essa solução pode ser facilmente generalizada com expressões regulares (e você pode adicionar um patternargumento, se não desejar que seus padrões sempre atinjam o início ou o final do nome do arquivo).

fralau
fonte
6

Usando geradores

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)
shantanoo
fonte
4

Outra variante muito legível para o Python 3.4+ está usando pathlib.Path.glob:

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

É simples tornar mais específico, por exemplo, procure apenas arquivos de origem Python que não são links simbólicos, também em todos os subdiretórios:

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

Aqui está minha função de propósito geral para isso. Ele retorna uma lista de caminhos de arquivos, em vez de nomes de arquivos, desde que achei mais útil. Ele possui alguns argumentos opcionais que o tornam versátil. Por exemplo, costumo usá-lo com argumentos como pattern='*.txt'ou 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)]
MarredCheese
fonte
2

Fornecerei uma amostra de um liner em que o caminho de origem e o tipo de arquivo possam ser fornecidos como entrada. O código retorna uma lista de nomes de arquivos com extensão csv. Use . caso todos os arquivos precisem ser retornados. Isso também verifica recursivamente os subdiretórios.

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

Modifique as extensões de arquivo e o caminho de origem, conforme necessário.

Vinodh Krishnaraju
fonte
1
Se você for usar glob, basta usar glob('**/*.csv', recursive=True). Não é necessário combinar isso com o os.walk()recursivo ( recursivee **são suportados desde o Python 3.5).
Martijn Pieters
2

Para python2: pip install rglob

import rglob
file_list=rglob.rglob("/home/base/dir/", "*")
print file_list
chris-piekarski
fonte
2

dircache é " Descontinuado desde a versão 2.6: O módulo dircache foi removido no Python 3.0."

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
shaji
fonte
17
dirchache é " Descontinuado desde a versão 2.6: O módulo dircache foi removido no Python 3.0."
21713 Daniel Reis