Как мне ограничить os.walk возвратом файлов только из того каталога, который я ему предоставил?
def _dir_list(self, dir_name, whitelist):
outputList = []
for root, dirs, files in os.walk(dir_name):
for f in files:
if os.path.splitext(f)[1] in whitelist:
outputList.append(os.path.join(root, f))
else:
self._email_to_("ignore")
return outputList
files_with_full_path = [f.path for f in os.scandir(dir) if f.is_file()]. Если вам нужны только имена файлов, используйте f.name вместо f.path. Это самое быстрое решение и намного быстрее, чем любой walk или listdir, см. stackoverflow.com/a/40347279/2441026.






Не используйте os.walk.
Пример:
import os
root = "C:\\"
for item in os.listdir(root):
if os.path.isfile(os.path.join(root, item)):
print item
@ 576i: это не делает различий между файлами и каталогами
@Alexandr os.path.isfile и os.path.isdir позволяют различать. Я не понимаю, так как os.path.isfile находится в образце кода с '08, а ваш комментарий от '16. Это явно лучший ответ, поскольку вы не собираетесь просматривать каталог, а хотите его перечислить.
@DanielF, я имел в виду, что вам нужно перебрать все элементы, в то время как walk сразу дает вам отдельные списки каталогов и файлов.
Ах хорошо. На самом деле ответ Алекса кажется лучше (с использованием .next()), и он намного ближе к вашей идее.
Python 3.5 имеет функцию os.scandir, которая обеспечивает более сложное взаимодействие файла или каталога-объекта. См. мой ответ ниже
Предложение использовать listdir - хорошее. Прямой ответ на ваш вопрос в Python 2 - root, dirs, files = os.walk(dir_name).next().
Эквивалентный синтаксис Python 3 - root, dirs, files = next(os.walk(dir_name))
О, я получал от этого какую-то забавную ошибку. ValueError: слишком много значений для распаковки
Хороший! Хотя по ощущениям хакер. Например, когда вы включаете двигатель, но даете ему сделать только один оборот, а затем вытаскиваете ключ, чтобы он умер.
Наткнулся на это; root, dirs, files = os.walk(dir_name).next() дает мне AttributeError: 'generator' object has no attribute 'next'
@Evan, вероятно, потому, что это из 2008 года и использует синтаксис Python 2. В Python 3 вы можете написать root, dirs, files = next(os.walk(dir_name)), и тогда переменные root, dirs, files будут соответствовать только переменным генератора на уровне dir_name.
Если у вас есть более сложные требования, чем только верхний каталог (например, игнорировать каталоги VCS и т. д.), Вы также можете изменить список каталогов, чтобы предотвратить повторное прохождение через них os.walk.
то есть:
def _dir_list(self, dir_name, whitelist):
outputList = []
for root, dirs, files in os.walk(dir_name):
dirs[:] = [d for d in dirs if is_good(d)]
for f in files:
do_stuff()
Примечание - будьте осторожны, чтобы изменить список, а не просто перепривязать его. Очевидно, что os.walk не знает о внешнем перепривязке.
Используйте функцию walklevel.
import os
def walklevel(some_dir, level=1):
some_dir = some_dir.rstrip(os.path.sep)
assert os.path.isdir(some_dir)
num_sep = some_dir.count(os.path.sep)
for root, dirs, files in os.walk(some_dir):
yield root, dirs, files
num_sep_this = root.count(os.path.sep)
if num_sep + level <= num_sep_this:
del dirs[:]
Он работает так же, как os.walk, но вы можете передать ему параметр level, который указывает, насколько глубока рекурсия.
Действительно ли эта функция «проходит» по всей структуре, а затем удаляет записи ниже определенной точки? Или творится что-то более умное? Я даже не знаю, как это проверить с помощью кода. --python новичок
@mathtick: когда какой-либо каталог находится на желаемом уровне или ниже, все его подкаталоги удаляются из списка подкаталогов для следующего поиска. Так что они не будут "гулять".
Я просто поставил +1, потому что не мог "удалить" каталоги. Я пробовал dirs = [] и dirs = None, но они не работали. map(dirs.remove, dirs) работал, но с некоторыми напечатанными нежелательными сообщениями «[None]». Итак, почему именно del dirs[:]?
отличный ответ. +1 только потому, что он работает с любым кодом, использующим os.walk.
Отличная функция - действительно полезная
Обратите внимание, что это не работает при использовании topdown=False в os.walk. См. 4-й абзац в документы: Modifying dirnames when topdown is False has no effect on the behavior of the walk, because in bottom-up mode the directories in dirnames are generated before dirpath itself is generated.
Я люблю это
@ZacharyYoung dirs = [] и dirs = None не будут работать, потому что они просто создают новый несвязанный объект и присваивают имя dirs. Необходимо изменить на месте исходный объект списка, а не имя dirs.
Как я могу распечатать каталоги уровня 1 в этом скрипте python с учетом допустимой папки? Подождите, мне нужно научиться использовать урожай.
Вы также можете сделать следующее:
for path, subdirs, files in os.walk(dir_name):
for name in files:
if path == ".": #this will filter the files in the current directory
#code here
Не будет ли эта процедура без надобности перебирать все подкаталоги и файлы?
Я думаю, что решение на самом деле очень простое.
использовать
break
чтобы выполнить только первую итерацию цикла for, должен быть более элегантный способ.
for root, dirs, files in os.walk(dir_name):
for f in files:
...
...
break
...
В первый раз, когда вы вызываете os.walk, он возвращает тюльпаны для текущего каталога, а затем в следующем цикле содержимое следующего каталога.
Возьмите оригинальный скрипт и просто добавьте перерыв.
def _dir_list(self, dir_name, whitelist):
outputList = []
for root, dirs, files in os.walk(dir_name):
for f in files:
if os.path.splitext(f)[1] in whitelist:
outputList.append(os.path.join(root, f))
else:
self._email_to_("ignore")
break
return outputList
Это должен был быть принятый ответ. Простое добавление «break» после цикла «for f in files» останавливает рекурсивность. Вы также можете убедиться, что topdown = True.
Та же идея с listdir, но короче:
[f for f in os.listdir(root_dir) if os.path.isfile(os.path.join(root_dir, f))]
Вот как я это решил
if recursive:
items = os.walk(target_directory)
else:
items = [next(os.walk(target_directory))]
...
При использовании listdir есть загвоздка. Os.path.isdir (идентификатор) должен быть абсолютным путем. Чтобы выбрать подкаталоги, выполните следующие действия:
for dirname in os.listdir(rootdir):
if os.path.isdir(os.path.join(rootdir, dirname)):
print("I got a subdirectory: %s" % dirname)
Альтернативой является переход в каталог для проведения тестирования без os.path.join ().
В Python 3 мне удалось это сделать:
import os
dir = "/path/to/files/"
#List all files immediately under this folder:
print ( next( os.walk(dir) )[2] )
#List all folders immediately under this folder:
print ( next( os.walk(dir) )[1] )
Это также работает для Python 2. Как получить второй уровень?
for path, dirs, files in os.walk('.'):
print path, dirs, files
del dirs[:] # go only one level deep
Вы можете использовать этот фрагмент
for root, dirs, files in os.walk(directory):
if level > 0:
# do some stuff
else:
break
level-=1
Я чувствовал себя так, как будто бросил свои 2 пенса.
baselevel = len(rootdir.split("\\"))
for subdirs, dirs, files in os.walk(rootdir):
curlevel = len(subdirs.split("\\"))
if curlevel <= baselevel + 1:
[do stuff]
создать список исключений, использовать fnmatch, чтобы пропустить структуру каталогов и выполнить процесс
excludes= ['a\*\b', 'c\d\e']
for root, directories, files in os.walk('Start_Folder'):
if not any(fnmatch.fnmatch(nf_root, pattern) for pattern in excludes):
for root, directories, files in os.walk(nf_root):
....
do the process
....
то же, что и для "включает":
if **any**(fnmatch.fnmatch(nf_root, pattern) for pattern in **includes**):
Почему бы просто не использовать range и os.walk в сочетании с zip? Не лучшее решение, но тоже подойдет.
Например так:
# your part before
for count, (root, dirs, files) in zip(range(0, 1), os.walk(dir_name)):
# logic stuff
# your later part
У меня работает на python 3.
Также: break, кстати, тоже попроще. (Посмотрите ответ от @Pieter)
Небольшое изменение в ответе Алекса, но с использованием __next__():
print(next(os.walk('d:/'))[2])
или же
print(os.walk('d:/').__next__()[2])
с [2], являющимся file в root, dirs, file, упомянутым в других ответах
Поскольку Python 3.5, вы можете использовать os.scandir вместо os.listdir. Вместо строк вы получаете взамен итератор объектов DirEntry. Из документов:
Using
scandir()instead oflistdir()can significantly increase the performance of code that also needs file type or file attribute information, becauseDirEntryobjects expose this information if the operating system provides it when scanning a directory. AllDirEntrymethods may perform a system call, butis_dir()andis_file()usually only require a system call for symbolic links;DirEntry.stat()always requires a system call on Unix but only requires one for symbolic links on Windows.
Вы можете получить доступ к имени объекта через DirEntry.name, которое тогда эквивалентно выводу os.listdir
Вы не только «можете» использовать, вы должен используете scandir(), так как это много быстрее, чем listdir(). Смотрите тесты здесь: stackoverflow.com/a/40347279/2441026.
корневая папка изменяется для каждого каталога, который находит os.walk. Я решил эту проверку, если root == directory
def _dir_list(self, dir_name, whitelist):
outputList = []
for root, dirs, files in os.walk(dir_name):
if root == dir_name: #This only meet parent folder
for f in files:
if os.path.splitext(f)[1] in whitelist:
outputList.append(os.path.join(root, f))
else:
self._email_to_("ignore")
return outputList
import os
def listFiles(self, dir_name):
names = []
for root, directory, files in os.walk(dir_name):
if root == dir_name:
for name in files:
names.append(name)
return names
Привет, Рич, добро пожаловать в Stack Overflow! Спасибо за этот фрагмент кода, который может предоставить некоторую краткосрочную помощь. Правильное объяснение значительно улучшит его долгосрочной ценности, показывающее, почему это хорошее решение проблемы, и сделало бы его более полезным для будущих читателей с другими подобными вопросами. Пожалуйста, редактировать свой ответ, чтобы добавить некоторые пояснения, включая сделанные вами предположения.
Это хороший пример Python
def walk_with_depth(root_path, depth):
if depth < 0:
for root, dirs, files in os.walk(root_path):
yield [root, dirs[:], files]
return
elif depth == 0:
return
base_depth = root_path.rstrip(os.path.sep).count(os.path.sep)
for root, dirs, files in os.walk(root_path):
yield [root, dirs[:], files]
cur_depth = root.count(os.path.sep)
if base_depth + depth <= cur_depth:
del dirs[:]
Другой случай, когда множество возможных подходов и все связанные с ними предостережения предполагают, что эту функциональность следует добавить в стандартную библиотеку Python.