python os.walk до определенного уровня
Я хочу создать программу, которая использует некоторый базовый код, чтобы прочитать папку и сказать мне, сколько файлов в папке. Вот как я это делаю в настоящее время:
import os
folders = ['Y:\\path1', 'Y:\\path2', 'Y:\\path3']
for stuff in folders:
for root, dirs, files in os.walk(stuff, topdown=True):
print("there are", len(files), "files in", root)
Это прекрасно работает, пока в "основной" папке не будет несколько папок, поскольку она может возвращать длинный, бесполезный список файлов из-за плохого управления папками / файлами. Так что я бы хотел перейти только на второй уровень. пример:
Main Folder
---file_i_want
---file_i_want
---Sub_Folder
------file_i_want <--*
------file_i want <--*
------Sub_Folder_2
---------file_i_dont_want
---------file_i_dont_want
Я знаю, как перейти на первый уровень с break
и с del dirs[:]
взято из этого поста, а также из этого поста.
import os
import pandas as pd
folders = ['Y:\\path1', 'Y:\\path2', 'Y:\\path3']
for stuff in folders:
for root, dirs, files in os.walk(stuff, topdown=True):
print("there are", len(files), "files in", root)
del dirs[:] # or a break here. does the same thing.
Но независимо от моих поисков, я не могу понять, как пройти два уровня. Может я просто не разбираюсь в других постах по этому поводу или как? Я думал что-то вроде del dirs[:2]
но безрезультатно. Может кто-нибудь направить меня или объяснить мне, как это сделать?
2 ответа
Вы могли бы сделать так:
for root,dirs,files in os.walk(stuff):
if root[len(stuff)+1:].count(os.sep)<2:
for f in files:
print(os.path.join(root,f))
ключ это: if root[len(stuff)+1:].count(os.sep)<2
Удаляет stuff
+ разделитель от root
, поэтому результат относительно stuff
, Просто посчитайте количество разделителей файлов, и не вводите условие, если вы не получите 0 или 1 разделители.
Конечно, он по-прежнему сканирует полную файловую структуру, но если это не очень глубоко, это сработает.
Другое решение было бы использовать только os.listdir
рекурсивно (с проверкой каталогов) с максимальным уровнем рекурсии, но это немного сложнее, если вам это не нужно. Поскольку это не так сложно, вот одна из реализаций:
def scanrec(root):
rval = []
def do_scan(start_dir,output,depth=0):
for f in os.listdir(start_dir):
ff = os.path.join(start_dir,f)
if os.path.isdir(ff):
if depth<2:
do_scan(ff,output,depth+1)
else:
output.append(ff)
do_scan(root,rval,0)
return rval
print(scanrec(stuff)) # prints the list of files not below 2 deep
Замечания: os.listdir
а также os.path.isfile
выполнить 2 stat
звонки так не оптимальны. В Python 3.5 использование os.scandir
мог бы избежать этого двойного звонка.
Вы можете сосчитать разделители и, если он имеет два уровня, удалить содержимое dirs
так walk
глубже не повторяется:
import os
MAX_DEPTH = 2
folders = ['Y:\\path1', 'Y:\\path2', 'Y:\\path3']
for stuff in folders:
for root, dirs, files in os.walk(stuff, topdown=True):
print("there are", len(files), "files in", root)
if root.count(os.sep) - stuff.count(os.sep) == MAX_DEPTH - 1:
del dirs[:]
Документация Python гласит следующее о поведении:
Когда topdown имеет значение True, вызывающий может изменить список dirnames на месте (возможно, используя del или slice назначением), и walk() будет возвращаться только в подкаталоги, чьи имена остаются в dirnames; это может использоваться для сокращения поиска, наложения определенного порядка посещения или даже для информирования walk() о каталогах, которые вызывающий абонент создает или переименовывает, прежде чем он возобновит walk() снова.
Обратите внимание, что вам необходимо учитывать разделители, присутствующие в folders
, Например, когда y:\path1
гулял корень y:\path
но вы не хотите останавливать рекурсию там.