Ітерація через каталоги з Python


157

Мені потрібно перебирати підкаталоги даного каталогу та шукати файли. Якщо я отримую файл, я мушу його відкрити, змінити вміст і замінити його власними рядками.

Я спробував це:

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

але я отримую помилку. Що я роблю неправильно?


12
"Помилка" - якась помилка зокрема?
Даніель Роузмен

1
Поясніть, будь ласка, трохи поясніть, що ви сподіваєтеся зробити з файлами / каталогами, як тільки ви пройдете їх, працюючи за призначенням? Будь ласка, надайте детальну інформацію про помилки.
ChrisProsser

1
Повідомлення про помилку, яке я отримую, - це те, що файл cool.txt не знайдено. У моїй тестовій папці у мене є інша папка, яка називається src, а в папці src у мене є інша папка, яка називається головною, у цій папці я cool.txt
Вовк

4
ви можете просто написати помилку у питанні? його все-таки надокучливо і непотрібно читати через коментарі, щоб знайти його.
Чарлі Паркер

1
через рік я не можу повірити, що я знову прошу надсилати помилку? @Wolf
Чарлі Паркер

Відповіді:


300

Фактична прогулянка по каталогах працює так, як ви її зашифрували. Якщо ви заміните вміст внутрішнього циклу простим 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))

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 = відкрити (subdir + '/' + файл , 'r') рядки = f.readlines () f.close () f = відкрити (subdir + '/' + файл, 'w') для рядка в рядках: newline = "hey I know" f.write (newline) f.close () Дякую людині. Її вирішено
Вовк

3
Привіт! Будь ласка, майте на увазі, що для "друку" в 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

1
Що тут краще для Python 3.6?
PhoenixDev

@PhoenixDev Я взагалі не чув, щоб один підхід рекомендувався над іншим взагалі. Я вважаю за краще використовувати pathlibсебе, здебільшого тому, що мені подобаються об'єктно-орієнтовані методи-синтаксиси. Є й інші відмінності, такі як бібліотека шляхів повертає конкретні класи шляху, а не рядки, а доступні функції відрізняються між бібліотеками (наприклад, os.path.expanduser('~')vs Path.home()). Перегляньте документацію і подивіться, який підхід ви віддаєте перевагу.
joelostblom

Замість того, щоб додавати **в глобальний шаблон, ви можете використовувати 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() із **/доданим перед заданою відносною схемою.


1
Це пітонічне рішення не містить перелічених прихованих файлів (aka dotfiles), а прийнятих.
ашразмун

@ashrasmun Те, що ви згадуєте, добре пояснено в docs.python.org/3/library/glob.html
CONvid19
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.