Фильтрующая ОС.прогулка() каталоги и файлы
Я ищу способ включить / исключить шаблоны файлов и исключить каталоги из вызова os.walk()
.
Вот что я сейчас делаю:
import fnmatch
import os
includes = ['*.doc', '*.odt']
excludes = ['/home/paulo-freitas/Documents']
def _filter(paths):
matches = []
for path in paths:
append = None
for include in includes:
if os.path.isdir(path):
append = True
break
if fnmatch.fnmatch(path, include):
append = True
break
for exclude in excludes:
if os.path.isdir(path) and path == exclude:
append = False
break
if fnmatch.fnmatch(path, exclude):
append = False
break
if append:
matches.append(path)
return matches
for root, dirs, files in os.walk('/home/paulo-freitas'):
dirs[:] = _filter(map(lambda d: os.path.join(root, d), dirs))
files[:] = _filter(map(lambda f: os.path.join(root, f), files))
for filename in files:
filename = os.path.join(root, filename)
print filename
Вопрос в том, есть ли лучший способ сделать это? Но как?8 ответов:
Это решение использует
fnmatch.translate
для преобразования шаблонов Глоб в регулярные выражения (предполагается, что includes используется только для файлов):import fnmatch import os import os.path import re includes = ['*.doc', '*.odt'] # for files only excludes = ['/home/paulo-freitas/Documents'] # for dirs and files # transform glob patterns to regular expressions includes = r'|'.join([fnmatch.translate(x) for x in includes]) excludes = r'|'.join([fnmatch.translate(x) for x in excludes]) or r'$.' for root, dirs, files in os.walk('/home/paulo-freitas'): # exclude dirs dirs[:] = [os.path.join(root, d) for d in dirs] dirs[:] = [d for d in dirs if not re.match(excludes, d)] # exclude/include files files = [os.path.join(root, f) for f in files] files = [f for f in files if not re.match(excludes, f)] files = [f for f in files if re.match(includes, f)] for fname in files: print fname
Из docs.python.org :
ОС.прогулка(сверху[, нисходящий=истина[, метод onerror=нет[, followlinks=ложь]]])
, Когда нисходящий правда, абонент может изменять список каталогов в место ... это может использоваться, чтобы сократить поиск ...
Я должен отметить, что приведенный выше код предполагает, чтоfor root, dirs, files in os.walk('/home/paulo-freitas', topdown=True): # excludes can be done with fnmatch.filter and complementary set, # but it's more annoying to read. dirs[:] = [d for d in dirs if d not in excludes] for pat in includes: for f in fnmatch.filter(files, pat): print os.path.join(root, f)
excludes
является шаблоном, а не полным путем. Вам нужно будет настроить понимание списка для фильтрации, еслиos.path.join(root, d) not in excludes
соответствует случаю OP.
Почему fnmatch?
import os excludes=.... for ROOT,DIR,FILES in os.walk("/path"): for file in FILES: if file.endswith(('doc','odt')): print file for directory in DIR: if not directory in excludes : print directory
Не проверено исчерпывающим образом
Dirtools идеально подходит для вашего случая использования:
from dirtools import Dir print(Dir('.', exclude_file='.gitignore').files())
Вот один из способов сделать это
import fnmatch import os excludes = ['/home/paulo-freitas/Documents'] matches = [] for path, dirs, files in os.walk(os.getcwd()): for eachpath in excludes: if eachpath in path: continue else: for result in [os.path.abspath(os.path.join(path, filename)) for filename in files if fnmatch.fnmatch(filename,'*.doc') or fnmatch.fnmatch(filename,'*.odt')]: matches.append(result) print matches
import os includes = ['*.doc', '*.odt'] excludes = ['/home/paulo-freitas/Documents'] def file_search(path, exe): for x,y,z in os.walk(path): for a in z: if a[-4:] == exe: print os.path.join(x,a) for x in includes: file_search(excludes[0],x)
Это пример исключения каталогов и файлов с помощью
os.walk()
:ignoreDirPatterns=[".git"] ignoreFilePatterns=[".php"] def copyTree(src, dest, onerror=None): src = os.path.abspath(src) src_prefix = len(src) + len(os.path.sep) for root, dirs, files in os.walk(src, onerror=onerror): for pattern in ignoreDirPatterns: if pattern in root: break else: #If the above break didn't work, this part will be executed for file in files: for pattern in ignoreFilePatterns: if pattern in file: break else: #If the above break didn't work, this part will be executed dirpath = os.path.join(dest, root[src_prefix:]) try: os.makedirs(dirpath,exist_ok=True) except OSError as e: if onerror is not None: onerror(e) filepath=os.path.join(root,file) shutil.copy(filepath,dirpath) continue;#If the above else didn't executed, this will be reached continue;#If the above else didn't executed, this will be reached
Python >=3.2 из-за
exist_ok
вmakedirs
Вышеописанные методы не сработали для меня.
Итак, это то, что я придумал с расширением моего первоначального ответа на другой вопрос.То, что сработало для меня, было:
if (not (str(root) + '/').startswith(tuple(exclude_foldr)))
Который скомпилировал путь и исключил кортеж из моих перечисленных папок.
Это дало мне точный результат, который я искал.Моя цель это, чтобы держать мой мак организовал.
Я могу искать любой
folder
поpath
,locate & move
спецификаfile.types
,ignore subfolders
и я упреждающеprompt the user
, если ониwant to move
файлы.Примечание:
Prompt
выполняется только один раз за запуск, а не за файлПо умолчанию приглашение по умолчанию принимает значение
NO
, Когда вы нажимаете enter вместо [y/N], и будет просто перечислять файлыPotential
, которые нужно переместить.Это только фрагмент моего GitHub пожалуйста, посетите для полного сценария.
Подсказка: прочитайте сценарий ниже, когда я добавлял информацию в строку о том, что я сделал.
#!/usr/bin/env python3 # ============================================================================= # Created On : MAC OSX High Sierra 10.13.6 (17G65) # Created On : Python 3.7.0 # Created By : Jeromie Kirchoff # ============================================================================= """THE MODULE HAS BEEN BUILD FOR KEEPING YOUR FILES ORGANIZED.""" # ============================================================================= from os import walk from os import path from shutil import move import getpass import click mac_username = getpass.getuser() includes_file_extensn = ([".jpg", ".gif", ".png", ".jpeg", ]) search_dir = path.dirname('/Users/' + mac_username + '/Documents/') target_foldr = path.dirname('/Users/' + mac_username + '/Pictures/Archive/') exclude_foldr = set([target_foldr, path.dirname('/Users/' + mac_username + '/Documents/GitHub/'), path.dirname('/Users/' + mac_username + '/Documents/Random/'), path.dirname('/Users/' + mac_username + '/Documents/Stupid_Folder/'), ]) if click.confirm("Would you like to move files?", default=False): question_moving = True else: question_moving = False def organize_files(): """THE MODULE HAS BEEN BUILD FOR KEEPING YOUR FILES ORGANIZED.""" # topdown=True required for filtering. # "Root" had all info i needed to filter folders not dir... for root, dir, files in walk(search_dir, topdown=True): for file in files: # creating a directory to str and excluding folders that start with if (not (str(root) + '/').startswith(tuple(exclude_foldr))): # showcase only the file types looking for if (file.endswith(tuple(includes_file_extensn))): # using path.normpath as i found an issue with double // # in file paths. filetomove = path.normpath(str(root) + '/' + str(file)) # forward slash required for both to split movingfileto = path.normpath(str(target_foldr) + '/' + str(file)) # Answering "NO" this only prints the files "TO BE Moved" print('Files To Move: ' + str(filetomove)) # This is using the prompt you answered at the beginning if question_moving is True: print('Moving File: ' + str(filetomove) + "\n To:" + str(movingfileto)) # This is the command that moves the file move(filetomove, movingfileto) pass # The rest is ignoring explicitly and continuing else: pass pass else: pass else: pass if __name__ == '__main__': organize_files()
Пример запуска моего скрипта из терминала:
$ python3 organize_files.py Exclude list: {'/Users/jkirchoff/Pictures/Archive', '/Users/jkirchoff/Documents/Stupid_Folder', '/Users/jkirchoff/Documents/Random', '/Users/jkirchoff/Documents/GitHub'} Files found will be moved to this folder:/Users/jkirchoff/Pictures/Archive Would you like to move files? No? This will just list the files. Yes? This will Move your files to the target folder. [y/N]:
Пример списка файлов:
Files To Move: /Users/jkirchoff/Documents/Archive/JayWork/1.custom-award-768x512.jpg Files To Move: /Users/jkirchoff/Documents/Archive/JayWork/10351458_318162838331056_9023492155204267542_n.jpg ...etc
Пример перемещения файлов:
Moving File: /Users/jkirchoff/Documents/Archive/JayWork/1.custom-award-768x512.jpg To: /Users/jkirchoff/Pictures/Archive/1.custom-award-768x512.jpg Moving File: /Users/jkirchoff/Documents/Archive/JayWork/10351458_318162838331056_9023492155204267542_n.jpg To: /Users/jkirchoff/Pictures/Archive/10351458_318162838331056_9023492155204267542_n.jpg ...