Diretório, subdiretório e arquivos da lista Python

130

Estou tentando criar um script para listar todos os diretórios, subdiretórios e arquivos em um determinado diretório.
Eu tentei isso:

import sys,os

root = "/home/patate/directory/"
path = os.path.join(root, "targetdirectory")

for r,d,f in os.walk(path):
    for file in f:
        print os.path.join(root,file)

Infelizmente, ele não funciona corretamente.
Eu recebo todos os arquivos, mas não os caminhos completos.

Por exemplo, se o dir struct seria:

/home/patate/directory/targetdirectory/123/456/789/file.txt

Seria impresso:

/home/patate/directory/targetdirectory/file.txt

O que eu preciso é o primeiro resultado. Qualquer ajuda seria muito apreciada! Obrigado.

thomytheyon
fonte

Respostas:

225

Use os.path.joinpara concatenar o diretório e o nome do arquivo :

for path, subdirs, files in os.walk(root):
    for name in files:
        print os.path.join(path, name)

Observe o uso de pathe não rootna concatenação, pois o uso rootseria incorreto.


No Python 3.4, o módulo pathlib foi adicionado para facilitar a manipulação de caminhos. Portanto, o equivalente a os.path.joinseria:

pathlib.PurePath(path, name)

A vantagem pathlibé que você pode usar uma variedade de métodos úteis nos caminhos. Se você usar a Pathvariante concreta, também poderá fazer chamadas reais do SO através delas, como entrar em um diretório, excluir o caminho, abrir o arquivo para o qual aponta e muito mais.

Eli Bendersky
fonte
esta é a única e útil resposta para as muitas perguntas que foram feitas sobre "como obter todos os arquivos recursivamente em python".
harrisonfooord
compreensão da lista: all_files = [os.path.join (caminho, nome) para o nome em arquivos de caminho, subdirs, arquivos em os.walk (pasta)]
Nir
45

Apenas no caso ... Obtendo todos os arquivos no diretório e subdiretórios correspondentes a algum padrão (* .py por exemplo):

import os
from fnmatch import fnmatch

root = '/some/directory'
pattern = "*.py"

for path, subdirs, files in os.walk(root):
    for name in files:
        if fnmatch(name, pattern):
            print os.path.join(path, name)
Ivan
fonte
10

Aqui está uma frase:

import os

[val for sublist in [[os.path.join(i[0], j) for j in i[2]] for i in os.walk('./')] for val in sublist]
# Meta comment to ease selecting text

O val for sublist in ...loop mais externo torna a lista unidimensional. O jloop coleta uma lista de todos os nomes de base de arquivos e os une ao caminho atual. Finalmente, o iloop itera sobre todos os diretórios e subdiretórios.

Este exemplo usa o caminho codificado ./na os.walk(...)chamada, você pode complementar qualquer sequência de caminho que desejar.

Nota: os.path.expandusere / ou os.path.expandvarspode ser usado para strings de caminhos como~/

Estendendo este exemplo:

É fácil adicionar testes de nome de base de arquivo e testes de nome de diretor.

Por exemplo, testando *.jpgarquivos:

... for j in i[2] if j.endswith('.jpg')] ...

Além disso, excluindo o .gitdiretório:

... for i in os.walk('./') if '.git' not in i[0].split('/')]
ThorSummoner
fonte
Funciona, mas para excluir o diretório .git, você precisa verificar se '.git' NÃO está no caminho.
Rdgz Roman
Sim. Deveria ser se '.git' não estiver em i [0] .split ('/')] #
1100 Roman Rdgz
Eu recomendaria os.walksobre um loop de dirlisting manual, os geradores são ótimos, use-os.
ThorSummoner
9

Não foi possível comentar, por isso, responda por escrito aqui. Esta é a linha mais clara que eu já vi:

import os
[os.path.join(path, name) for path, subdirs, files in os.walk(root) for name in files]
Mong H. Ng
fonte
4

Você pode dar uma olhada nesta amostra que fiz. Ele usa a função os.path.walk, que está obsoleta. Use uma lista para armazenar todos os caminhos de arquivo

root = "Your root directory"
ex = ".txt"
where_to = "Wherever you wanna write your file to"
def fileWalker(ext,dirname,names):
    '''
    checks files in names'''
    pat = "*" + ext[0]
    for f in names:
        if fnmatch.fnmatch(f,pat):
            ext[1].append(os.path.join(dirname,f))


def writeTo(fList):

    with open(where_to,"w") as f:
        for di_r in fList:
            f.write(di_r + "\n")






if __name__ == '__main__':
    li = []
    os.path.walk(root,fileWalker,[ex,li])

    writeTo(li)
devsaw
fonte
4

Uma linha um pouco mais simples:

import os
from itertools import product, chain

chain.from_iterable([[os.sep.join(w) for w in product([i[0]], i[2])] for i in os.walk(dir)])
Daniel
fonte
2

Como todos os exemplos aqui estão apenas usando walk(com join), eu gostaria de mostrar um bom exemplo e comparação com listdir:

import os, time

def listFiles1(root): # listdir
    allFiles = []; walk = [root]
    while walk:
        folder = walk.pop(0)+"/"; items = os.listdir(folder) # items = folders + files
        for i in items: i=folder+i; (walk if os.path.isdir(i) else allFiles).append(i)
    return allFiles

def listFiles2(root): # listdir/join (takes ~1.4x as long) (and uses '\\' instead)
    allFiles = []; walk = [root]
    while walk:
        folder = walk.pop(0); items = os.listdir(folder) # items = folders + files
        for i in items: i=os.path.join(folder,i); (walk if os.path.isdir(i) else allFiles).append(i)
    return allFiles

def listFiles3(root): # walk (takes ~1.5x as long)
    allFiles = []
    for folder, folders, files in os.walk(root):
        for file in files: allFiles+=[folder.replace("\\","/")+"/"+file] # folder+"\\"+file still ~1.5x
    return allFiles

def listFiles4(root): # walk/join (takes ~1.6x as long) (and uses '\\' instead)
    allFiles = []
    for folder, folders, files in os.walk(root):
        for file in files: allFiles+=[os.path.join(folder,file)]
    return allFiles


for i in range(100): files = listFiles1("src") # warm up

start = time.time()
for i in range(100): files = listFiles1("src") # listdir
print("Time taken: %.2fs"%(time.time()-start)) # 0.28s

start = time.time()
for i in range(100): files = listFiles2("src") # listdir and join
print("Time taken: %.2fs"%(time.time()-start)) # 0.38s

start = time.time()
for i in range(100): files = listFiles3("src") # walk
print("Time taken: %.2fs"%(time.time()-start)) # 0.42s

start = time.time()
for i in range(100): files = listFiles4("src") # walk and join
print("Time taken: %.2fs"%(time.time()-start)) # 0.47s

Então, como você pode ver por si mesmo, a listdirversão é muito mais eficiente. (e isso joiné lento)

Poça
fonte