Как мне ограничить 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, becauseDirEntry
objects expose this information if the operating system provides it when scanning a directory. AllDirEntry
methods 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.