Iterando Diretórios com Python


158

Eu preciso percorrer os subdiretórios de um determinado diretório e procurar arquivos. Se eu receber um arquivo, tenho que abri-lo, alterar o conteúdo e substituí-lo por minhas próprias linhas.

Eu tentei isso:

import os

rootdir ='C:/Users/sid/Desktop/test'

for subdir, dirs, files in os.walk(rootdir):
    for file in files:
        f=open(file,'r')
        lines=f.readlines()
        f.close()
        f=open(file,'w')
        for line in lines:
            newline = "No you are not"
            f.write(newline)
        f.close()

mas estou recebendo um erro. O que estou fazendo de errado?


12
"Um erro" - algum erro em particular?
Daniel Roseman

1
Por favor, você poderia explicar um pouco sobre o que você espera fazer com os arquivos / diretórios, depois de passar por eles trabalhando como pretendido? Também forneça detalhes do erro.
ChrisProsser

1
A mensagem de erro que estou recebendo é que o arquivo cool.txt não foi encontrado. No meu teste pasta eu tenho uma outra pasta chamada src e no src pasta Eu tenho uma outra pasta chamada principal, nesta pasta eu tenho cool.txt
Lobo

4
você pode simplesmente escrever o erro na pergunta? é irritante e desnecessário ter que ler os comentários para encontrá-lo.
Charlie Parker

1
mais de um ano depois, não acredito que estou de volta solicitando a publicação do erro? @Wolf
Charlie Parker

Respostas:


301

O passeio real pelos diretórios funciona como você o codificou. Se você substituir o conteúdo do loop interno por uma printdeclaração simples , poderá ver que cada arquivo foi encontrado:

import os
rootdir = 'C:/Users/sid/Desktop/test'

for subdir, dirs, files in os.walk(rootdir):
    for file in files:
        print os.path.join(subdir, file)

Se você ainda receber erros ao executar o procedimento acima, forneça a mensagem de erro.


Atualizado para Python3

import os
rootdir = 'C:/Users/sid/Desktop/test'

for subdir, dirs, files in os.walk(rootdir):
    for file in files:
        print(os.path.join(subdir, file))

1
C: / Usuários / sid / Desktop / teste \ src \ app / cool.txt C: / Usuários / sid / Desktop / teste \ src \ app / woohoo.txt Ya na declaração aberta do meu código, acho que tenho que forneça o caminho absoluto para o arquivo. import os rootdir = 'C: / Usuários / spemmara / Desktop / test / src / app /' para subdir, dirs, arquivos no os.walk (rootdir): para arquivo nos arquivos: f = open (subdir + '/' + file , 'r') linhas = f.readlines () f.close () f = aberto (subdireta + '/' + arquivo, 'w') para a linha nas linhas: newline = "ei, eu sei" f.write (newline) f.close () Obrigado cara. Resolvido
Wolf

3
Oi! Lembre-se de que a "impressão" no python 3 exige parênteses, caso contrário, retorna um erro de sintaxe. Espero que isto ajude!
Tommaso Di Noto

14

Outra maneira de retornar todos os arquivos nos subdiretórios é usar o pathlibmódulo , introduzido no Python 3.4, que fornece uma abordagem orientada a objetos para lidar com os caminhos do sistema de arquivos (Pathlib também está disponível no Python 2.7 através do módulo pathlib2 no PyPi ):

from pathlib import Path

rootdir = Path('C:/Users/sid/Desktop/test')
# Return a list of regular files only, not directories
file_list = [f for f in rootdir.glob('**/*') if f.is_file()]

# For absolute paths instead of relative the current dir
file_list = [f for f in rootdir.resolve().glob('**/*') if f.is_file()]

Desde o Python 3.5, o globmódulo também oferece suporte à localização de arquivos recursivos:

import os
from glob import iglob

rootdir_glob = 'C:/Users/sid/Desktop/test/**/*' # Note the added asterisks
# This will return absolute paths
file_list = [f for f in iglob('**/*', recursive=True) if os.path.isfile(f)]

A file_listpartir de qualquer uma das abordagens acima pode ser iterada sem a necessidade de um loop aninhado:

for f in file_list:
    print(f) # Replace with desired operations

1
O que é preferível aqui para o Python 3.6?
PhoenixDev

@PhoenixDev Não ouvi falar de uma abordagem recomendada sobre a outra em geral. Eu prefiro pathlibme usar , principalmente porque gosto da sintaxe dos métodos orientados a objetos. Existem outras diferenças, como a biblioteca de caminhos retorna classes de caminhos específicos em vez de cadeias, e as funções disponíveis diferem entre as bibliotecas (por exemplo, os.path.expanduser('~')vs Path.home()). Navegue pela documentação e veja qual abordagem você prefere.
Joelostblom

Em vez de adicionar **no padrão glob, você pode usar rglob.
Georgy

12

A partir de 2020 , glob.iglob(path/**, recursive=True)parece a solução mais pitônica , ou seja:

import glob, os

for filename in glob.iglob('/pardadox-music/**', recursive=True):
    if os.path.isfile(filename): # filter dirs
        print(filename)

Resultado:

/pardadox-music/modules/her1.mod
/pardadox-music/modules/her2.mod
...

Notas:
1 - glob.iglob

glob.iglob(pathname, recursive=False)

Retorne um iterador que produz os mesmos valores que glob()sem realmente armazená-los todos simultaneamente.

2 - Se recursivo for True, o padrão '**'corresponderá a todos os arquivos e zero ou mais directoriese subdirectories.

3 - Se o diretório contiver arquivos começando com,  .eles não serão correspondidos por padrão. Por exemplo, considere um diretório que contém  card.gif e .card.gif:

>>> import glob
>>> glob.glob('*.gif') ['card.gif'] 
>>> glob.glob('.c*')['.card.gif']

4 - Você também pode usar rglob(pattern), que é o mesmo que chamar  glob() com **/adicionado na frente do padrão relativo fornecido.


1
Este pythônico solução não listar arquivos ocultos (aka dotfiles) enquanto o aceite faz.
ashrasmun 8/09/19

@ashrasmun O que você mencionou está bem explicado em docs.python.org/3/library/glob.html
CONvid19
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.