Итерация по каталогам с помощью Python

158

Мне нужно перебрать подкаталоги данного каталога и искать файлы. Если я получаю файл, я должен открыть его, изменить содержимое и заменить его собственными строками.

Я попробовал это:

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

но я получаю ошибку. Что я делаю не так?

волк
источник
13
«Ошибка» - какая-то конкретная ошибка?
Даниэль Роузман
1
Не могли бы вы немного рассказать о том, что вы надеетесь сделать с файлами / каталогами после того, как вы научитесь работать с ними, как задумано? Также, пожалуйста, предоставьте детали ошибки.
ChrisProsser
1
Я получаю сообщение об ошибке: файл cool.txt не найден. В моей тестовой папке у меня есть другая папка с именем src, и в папке src у меня есть другая папка с именем main, в этой папке у меня есть cool.txt
Wolf
4
Вы можете просто написать ошибку в вопросе? это вне раздражает и не нужно, чтобы прочитать комментарии, чтобы найти его.
Чарли Паркер
1
более года спустя я не могу поверить, что вернулся с просьбой опубликовать сообщение об ошибке? @Wolf
Чарли Паркер

Ответы:

301

Фактическая прогулка по каталогам работает так, как вы ее закодировали. Если вы замените содержимое внутреннего цикла простым printоператором, вы увидите, что каждый файл найден:

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)

Если вы все еще получаете ошибки при запуске выше, пожалуйста, предоставьте сообщение об ошибке.


Обновлено для 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))
ChrisProsser
источник
1
C: / Users / sid / Desktop / test \ src \ app / cool.txt C: / Users / sid / Desktop / test \ src \ app / woohoo.txt Я в открытом заявлении моего кода, я думаю, что я должен дать абсолютный путь к файлу. import os rootdir = 'C: / Users / spemmara / Desktop / test / src / app /' для subdir, dirs, файлов в os.walk (rootdir): для файла в файлах: f = open (subdir + '/' + file , 'r') lines = f.readlines () f.close () f = open (subdir + '/' + file, 'w') для строки в строках: newline = "эй, я знаю" f.write (newline) f.close () Спасибо, мужчина. Это решено
Wolf
3
Здравствуй! Пожалуйста, имейте в виду, что «print» в python 3 требует скобок, в противном случае возвращает синтаксическую ошибку. Надеюсь это поможет!
Томмазо Ди Ното
14

Другой способ возвращения всех файлов в подкаталогах, чтобы использовать в pathlibмодуль , введенный в Python 3.4, который обеспечивает ориентированный объектный подход к обработке путей файловой системы (Pathlib также доступна на Python 2.7 с помощью модуля pathlib2 на 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()]

Начиная с Python 3.5, globмодуль также поддерживает рекурсивный поиск файлов:

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

file_listОт любого из вышеуказанных подходов может повторяться в течение без необходимости вложенного цикла:

for f in file_list:
    print(f) # Replace with desired operations
joelostblom
источник
1
Что здесь предпочтительнее для Python 3.6?
PhoenixDev
@PhoenixDev Я не слышал, чтобы один подход был рекомендован по сравнению с другим в целом. Я предпочитаю использовать pathlibсебя, в основном потому, что мне нравится объектно-ориентированный метод-синтаксис. Существуют и другие различия, например, библиотека путей возвращает определенные классы путей, а не строки, и доступные функции различаются между библиотеками (например, os.path.expanduser('~')vs Path.home()). Просмотрите документацию и посмотрите, какой подход вы предпочитаете.
joelostblom
Вместо добавления **в шаблон glob, вы можете использовать rglob.
Георгий
12

По состоянию на 2020 г. , glob.iglob(path/**, recursive=True)кажется наиболее вещим решение, а именно:

import glob, os

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

Вывод:

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

Примечания:
1 - glob.iglob

glob.iglob(pathname, recursive=False)

Вернуть итератор, который выдает те же значения, что и glob()без фактического сохранения их всех одновременно.

2 - если рекурсивный True, шаблон '**'будет соответствовать любым файлам и нулю или более directoriesи subdirectories.

3 - Если каталог содержит файлы, начинающиеся с,  .они не будут сопоставлены по умолчанию. Например, рассмотрим каталог, содержащий  card.gif и .card.gif:

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

4 - Вы также можете использовать rglob(pattern), что аналогично вызову  glob() с **/добавленным перед данным относительным шаблоном.

CONvid19
источник
1
Это питоническое решение не перечисляет скрытые файлы (то есть точечные файлы), в то время как принятый делает.
ашрасмун
@ashrasmun То, что вы упоминаете, хорошо объяснено в docs.python.org/3/library/glob.html
CONvid19