У меня есть файл, который может находиться в разных местах на каждом компьютере пользователя. Есть ли способ реализовать поиск файла? Как я могу передать имя файла и дерево каталогов для поиска?
os.walk - это ответ, это найдет первое совпадение:
import os
def find(name, path):for root, dirs, files in os.walk(path):if name in files:return os.path.join(root, name)
И это найдет все совпадения:
def find_all(name, path):
result =[]for root, dirs, files in os.walk(path):if name in files:
result.append(os.path.join(root, name))return result
И это будет соответствовать шаблону:
import os, fnmatch
def find(pattern, path):
result =[]for root, dirs, files in os.walk(path):for name in files:if fnmatch.fnmatch(name, pattern):
result.append(os.path.join(root, name))return result
find('*.txt','/path/to/dir')
Обратите внимание, что эти примеры будут искать только файлы, а не каталоги с тем же именем. Если вы хотите найти в каталоге какой-либо объект с таким именем, вы, возможно, захотите использоватьif name in file or name in dirs
Марк Э. Гамильтон
9
Будьте осторожны с чувствительностью к регистру. for name in files:не удастся найти, super-photo.jpgкогда он находится super-photo.JPGв файловой системе. (Я бы хотел вернуться на час моей жизни ;-) Немного грязное исправлениеif str.lower(name) in [x.lower() for x in files]
Мэтт Уилки
Как насчет использования yield вместо подготовки списка результатов? ..... if fnmatch.fnmatch (name, pattern): yield os.path.join (root, name)
Берчи
Пожалуйста, подумайте об обновлении своего ответа на примитивы Python 3.x
Дима Тиснек
1
Список понимания может заменить функцию, например find_all: res = [os.path.join (root, name) для root, dirs, files in os.walk (path) if name in files]
Nir
23
Я использовал версию os.walkи в более крупном каталоге время около 3,5 секунд. Я попробовал два случайных решения без особого улучшения, а потом просто сделал:
paths =[line[2:]for line in subprocess.check_output("find . -iname '*.txt'", shell=True).splitlines()]
Пока это только POSIX, у меня получилось 0,25 сек.
Исходя из этого, я считаю, что вполне возможно оптимизировать весь поиск независимо от платформы, но именно здесь я остановил исследование.
Если вы используете Python в Ubuntu и хотите, чтобы он работал только в Ubuntu, значительно более быстрым способом является использование такой locateпрограммы терминала .
search_resultsявляется одним listиз абсолютных путей к файлам. Это в 10 000 раз быстрее, чем методы, описанные выше, а один поиск, который я сделал, был в ~ 72 000 раз быстрее.
В частности, используйте scandir.walk()ответ @ Nadia. Обратите внимание, что если вы используете Python 3.5+, os.walk()у вас scandir.walk()уже есть ускорение. Кроме того, PEP 471 , вероятно, лучший документ для информации, чем этот выпуск.
Бен Хойт
3
Если вы работаете с Python 2, у вас есть проблема с бесконечной рекурсией в окнах, вызванная саморекламными символическими ссылками.
Этот скрипт не будет следовать этим. Обратите внимание, что это зависит от Windows !
import os
from scandir import scandir
import ctypes
def is_sym_link(path):# http://stackoverflow.com/a/35915819
FILE_ATTRIBUTE_REPARSE_POINT =0x0400return os.path.isdir(path)and(ctypes.windll.kernel32.GetFileAttributesW(unicode(path))& FILE_ATTRIBUTE_REPARSE_POINT)def find(base, filenames):
hits =[]def find_in_dir_subdir(direc):
content = scandir(direc)for entry in content:if entry.name in filenames:
hits.append(os.path.join(direc, entry.name))elif entry.is_dir()andnot is_sym_link(os.path.join(direc, entry.name)):try:
find_in_dir_subdir(os.path.join(direc, entry.name))exceptUnicodeDecodeError:print"Could not resolve "+ os.path.join(direc, entry.name)continueifnot os.path.exists(base):returnelse:
find_in_dir_subdir(base)return hits
Он возвращает список со всеми путями, которые указывают на файлы в списке имен файлов. Использование:
Ниже мы используем логический аргумент «first» для переключения между первым совпадением и всеми совпадениями (значение по умолчанию эквивалентно «find. -Name file»):
import os
def find(root, file, first=False):for d, subD, f in os.walk(root):if file in f:print("{0} : {1}".format(file, d))if first ==True:break
Ответ очень похож на существующие, но немного оптимизирован.
Таким образом, вы можете найти любые файлы или папки по шаблону:
def iter_all(pattern, path):return(
os.path.join(root, entry)for root, dirs, files in os.walk(path)for entry in dirs + files
if pattern.match(entry))
либо по подстроке:
def iter_all(substring, path):return(
os.path.join(root, entry)for root, dirs, files in os.walk(path)for entry in dirs + files
if substring in entry
)
или используя предикат:
def iter_all(predicate, path):return(
os.path.join(root, entry)for root, dirs, files in os.walk(path)for entry in dirs + files
if predicate(entry))
для поиска только файлов или только папок - замените, например, «каталоги + файлы» только «каталогами» или только «файлами», в зависимости от того, что вам нужно.
Ответ SARose работал у меня, пока я не обновился с Ubuntu 20.04 LTS. Небольшое изменение, которое я внес в его код, заставляет его работать в последней версии Ubuntu.
Ответы:
os.walk - это ответ, это найдет первое совпадение:
И это найдет все совпадения:
И это будет соответствовать шаблону:
источник
if name in file or name in dirs
for name in files:
не удастся найти,super-photo.jpg
когда он находитсяsuper-photo.JPG
в файловой системе. (Я бы хотел вернуться на час моей жизни ;-) Немного грязное исправлениеif str.lower(name) in [x.lower() for x in files]
Я использовал версию
os.walk
и в более крупном каталоге время около 3,5 секунд. Я попробовал два случайных решения без особого улучшения, а потом просто сделал:Пока это только POSIX, у меня получилось 0,25 сек.
Исходя из этого, я считаю, что вполне возможно оптимизировать весь поиск независимо от платформы, но именно здесь я остановил исследование.
источник
Если вы используете Python в Ubuntu и хотите, чтобы он работал только в Ubuntu, значительно более быстрым способом является использование такой
locate
программы терминала .search_results
является однимlist
из абсолютных путей к файлам. Это в 10 000 раз быстрее, чем методы, описанные выше, а один поиск, который я сделал, был в ~ 72 000 раз быстрее.источник
В Python 3.4 или новее вы можете использовать pathlib для рекурсивного подстановки:
Ссылка: https://docs.python.org/3/library/pathlib.html#pathlib.Path.glob
В Python 3.5 или новее вы также можете выполнять рекурсивную глобализацию следующим образом:
Ссылка: https://docs.python.org/3/library/glob.html#glob.glob
источник
Для быстрого поиска независимо от ОС используйте
scandir
https://github.com/benhoyt/scandir/#readme
Прочтите http://bugs.python.org/issue11406, чтобы узнать, почему.
источник
scandir.walk()
ответ @ Nadia. Обратите внимание, что если вы используете Python 3.5+,os.walk()
у васscandir.walk()
уже есть ускорение. Кроме того, PEP 471 , вероятно, лучший документ для информации, чем этот выпуск.Если вы работаете с Python 2, у вас есть проблема с бесконечной рекурсией в окнах, вызванная саморекламными символическими ссылками.
Этот скрипт не будет следовать этим. Обратите внимание, что это зависит от Windows !
Он возвращает список со всеми путями, которые указывают на файлы в списке имен файлов. Использование:
источник
Ниже мы используем логический аргумент «first» для переключения между первым совпадением и всеми совпадениями (значение по умолчанию эквивалентно «find. -Name file»):
источник
Ответ очень похож на существующие, но немного оптимизирован.
Таким образом, вы можете найти любые файлы или папки по шаблону:
либо по подстроке:
или используя предикат:
для поиска только файлов или только папок - замените, например, «каталоги + файлы» только «каталогами» или только «файлами», в зависимости от того, что вам нужно.
С уважением.
источник
Ответ SARose работал у меня, пока я не обновился с Ubuntu 20.04 LTS. Небольшое изменение, которое я внес в его код, заставляет его работать в последней версии Ubuntu.
источник