Чтение рекурсивной папки Python - PullRequest
176 голосов
/ 06 февраля 2010

У меня есть фон C ++ / Obj-C, и я только открываю Python (пишу его около часа). Я пишу скрипт для рекурсивного чтения содержимого текстовых файлов в структуре папок.

Проблема, с которой я столкнулся, состоит в том, что написанный мной код будет работать только для одной папки. Я могу понять, почему в коде (см. #hardcoded path) я просто не знаю, как мне двигаться дальше с Python, поскольку мой опыт работы с ним только новый.

Код Python:

import os
import sys

rootdir = sys.argv[1]

for root, subFolders, files in os.walk(rootdir):

    for folder in subFolders:
        outfileName = rootdir + "/" + folder + "/py-outfile.txt" # hardcoded path
        folderOut = open( outfileName, 'w' )
        print "outfileName is " + outfileName

        for file in files:
            filePath = rootdir + '/' + file
            f = open( filePath, 'r' )
            toWrite = f.read()
            print "Writing '" + toWrite + "' to" + filePath
            folderOut.write( toWrite )
            f.close()

        folderOut.close()

Ответы [ 9 ]

293 голосов
/ 06 февраля 2010

Убедитесь, что вы понимаете три возвращаемых значения os.walk:

for root, subdirs, files in os.walk(rootdir):

имеет следующее значение:

  • root: текущий путь, который "прошел"
  • subdirs: файлы в root каталога типа
  • files: файлы в root (не в subdirs) другого типа, кроме каталога

И, пожалуйста, используйте os.path.join вместо конкатенации с косой чертой! Ваша проблема filePath = rootdir + '/' + file - вы должны объединить текущую "пройденную" папку вместо самой верхней папки. Так что это должно быть filePath = os.path.join(root, file). Кстати, «файл» является встроенным, поэтому его обычно не используют в качестве имени переменной.

Другая проблема - ваши циклы, которые должны быть такими, например:

import os
import sys

walk_dir = sys.argv[1]

print('walk_dir = ' + walk_dir)

# If your current working directory may change during script execution, it's recommended to
# immediately convert program arguments to an absolute path. Then the variable root below will
# be an absolute path as well. Example:
# walk_dir = os.path.abspath(walk_dir)
print('walk_dir (absolute) = ' + os.path.abspath(walk_dir))

for root, subdirs, files in os.walk(walk_dir):
    print('--\nroot = ' + root)
    list_file_path = os.path.join(root, 'my-directory-list.txt')
    print('list_file_path = ' + list_file_path)

    with open(list_file_path, 'wb') as list_file:
        for subdir in subdirs:
            print('\t- subdirectory ' + subdir)

        for filename in files:
            file_path = os.path.join(root, filename)

            print('\t- file %s (full path: %s)' % (filename, file_path))

            with open(file_path, 'rb') as f:
                f_content = f.read()
                list_file.write(('The file %s contains:\n' % filename).encode('utf-8'))
                list_file.write(f_content)
                list_file.write(b'\n')

Если вы не знали, оператор with для файлов - это сокращение:

with open('filename', 'rb') as f:
    dosomething()

# is effectively the same as

f = open('filename', 'rb')
try:
    dosomething()
finally:
    f.close()
61 голосов
/ 18 июля 2017

Если вы используете Python 3.5 или выше, вы можете сделать это в 1 строку.

import glob

for filename in glob.iglob(root_dir + '**/*.txt', recursive=True):
     print(filename)

Как указано в документации

Если для recursive задано значение true, шаблон ** будет соответствовать любым файлам и нулю или более каталогов и подкаталогов.

Если вы хотите каждый файл, вы можете использовать

import glob

for filename in glob.iglob(root_dir + '**/*', recursive=True):
     print(filename)
34 голосов
/ 06 февраля 2010

Согласитесь с Дейвом Уэббом, os.walk даст элемент для каждого каталога в дереве. На самом деле вам просто не нужно заботиться о subFolders.

Код, как это должно работать:

import os
import sys

rootdir = sys.argv[1]

for folder, subs, files in os.walk(rootdir):
    with open(os.path.join(folder, 'python-outfile.txt'), 'w') as dest:
        for filename in files:
            with open(os.path.join(folder, filename), 'r') as src:
                dest.write(src.read())
5 голосов
/ 16 марта 2019
import glob
import os

root_dir = <root_dir_here>

for filename in glob.iglob(root_dir + '**/**', recursive=True):
    if os.path.isfile(filename):
        with open(filename,'r') as file:
            print(file.read())

**/** используется для рекурсивного получения всех файлов, включая directory.

if os.path.isfile(filename) используется для проверки, является ли переменная filename file или directory, если это файл, то мы можем прочитать этот файл. Здесь я печатаю файл.

3 голосов
/ 06 февраля 2010

используйте os.path.join() для построения своих путей - это аккуратнее:

import os
import sys
rootdir = sys.argv[1]
for root, subFolders, files in os.walk(rootdir):
    for folder in subFolders:
        outfileName = os.path.join(root,folder,"py-outfile.txt")
        folderOut = open( outfileName, 'w' )
        print "outfileName is " + outfileName
        for file in files:
            filePath = os.path.join(root,file)
            toWrite = open( filePath).read()
            print "Writing '" + toWrite + "' to" + filePath
            folderOut.write( toWrite )
        folderOut.close()
2 голосов
/ 05 февраля 2019

Если вы хотите получить список всех путей под данным каталогом (например, find . в оболочке):

   files = [ 
       os.path.join(parent, name)
       for (parent, subdirs, files) in os.walk(YOUR_DIRECTORY)
       for name in files + subdirs
   ]

Чтобы включить только полные пути к файлам в базовом каталоге, не указывайте + subdirs.

1 голос
/ 13 июля 2017

Попробуйте это:

import os
import sys

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

    for file in os.listdir(root):

        filePath = os.path.join(root, file)

        if os.path.isdir(filePath):
            pass

        else:
            f = open (filePath, 'r')
            # Do Stuff
0 голосов
/ 23 августа 2011

os.walk делает рекурсивный обход по умолчанию. Для каждого каталога, начиная с корня, выдается 3 кортежа (dirpath, dirnames, filenames)

from os import walk
from os.path import splitext, join

def select_files(root, files):
    """
    simple logic here to filter out interesting files
    .py files in this example
    """

    selected_files = []

    for file in files:
        #do concatenation here to get full path 
        full_path = join(root, file)
        ext = splitext(file)[1]

        if ext == ".py":
            selected_files.append(full_path)

    return selected_files

def build_recursive_dir_tree(path):
    """
    path    -    where to begin folder scan
    """
    selected_files = []

    for root, dirs, files in walk(path):
        selected_files += select_files(root, files)

    return selected_files
0 голосов
/ 06 февраля 2010

Мне кажется, проблема в том, что вы неправильно обрабатываете вывод os.walk.

Во-первых, измените:

filePath = rootdir + '/' + file

до:

filePath = root + '/' + file

rootdir - ваш фиксированный начальный каталог; root - это каталог, возвращаемый os.walk.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...