Чтение рекурсивной папки Python
у меня есть фон 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()
7 ответов:
убедитесь, что вы понимаете три возвращаемых значения
os.walk:for root, subdirs, files in os.walk(rootdir):имеет следующее значение:
root: текущий путь, который "прошел через"subdirs: файлыrootкаталога типаfiles: файлыroot(неsubdirs) типа, отличного от каталогаи, пожалуйста, используйте
os.path.joinвместо сцепления с косой чертой! Ваша проблемаfilePath = rootdir + '/' + file- вы должны объедините текущую папку "walked" вместо самой верхней папки. Так что это должно быть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()
согласен с Дэйвом Уэббом,
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())
Если вы используете Python 3.5+ или выше, вы можете сделать это в 1 строке.
import glob for filename in glob.iglob(root_dir + '**/*.txt', recursive=True): print(filename)Как уже упоминалось в документации
Если рекурсивно верно, шаблон '* * ' будет соответствовать любым файлам и нулю или более каталогов и подкаталогов.
Если вы хотите каждый файл, вы можете использовать
import glob for filename in glob.iglob(root_dir + '**/*', recursive=True): print(filename)
использовать
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()
попробуйте это:
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
os.walkрекурсивная прогулка по умолчанию. Для всех каталогов, начиная с корневого, он дает 3-кортеж (dirpath, каталогов, файлов)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
Я думаю, проблема в том, что вы не обрабатываете вывод
os.walkправильно.во-первых, изменить:
filePath = rootdir + '/' + fileto:
filePath = root + '/' + file
rootdir- Это ваш фиксированный каталога;root- каталог, возвращенныеos.walk.во-вторых, вам не нужно отступать от цикла обработки файлов, так как нет смысла запускать это для каждого подкаталога. Вы получите
rootустановить для каждого подкаталога. Вам не нужно обрабатывать подкаталоги вручную, если вы не хотите что-то делать с самими каталогами.
Comments