У меня есть файл, который может находиться в другом месте на каждом пользовательском компьютере. Есть ли способ реализовать поиск файла? Способ, которым я могу передать имя файла и дерево каталогов для поиска в?
Найти файл в python
Ответ 1
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')
Ответ 2
Я использовал версию os.walk
, а в более крупном каталоге - времена около 3,5 секунд. Я попробовал два случайных решения без больших улучшений, а затем просто:
paths = [line[2:] for line in subprocess.check_output("find . -iname '*.txt'", shell=True).splitlines()]
Пока он только POSIX, я получил 0,25 с.
Из этого я считаю, что вполне возможно оптимизировать весь процесс поиска много независимым от платформы способом, но именно здесь я остановил исследование.
Ответ 3
Если вы работаете с Python 2, у вас есть проблема с бесконечной рекурсией на окнах, вызванная самоназывающимися символическими ссылками.
Этот script будет избегать следующих действий. Обратите внимание, что это для Windows!
import os
from scandir import scandir
import ctypes
def is_sym_link(path):
# http://stackoverflow.com/a/35915819
FILE_ATTRIBUTE_REPARSE_POINT = 0x0400
return 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() and not is_sym_link(os.path.join(direc, entry.name)):
try:
find_in_dir_subdir(os.path.join(direc, entry.name))
except UnicodeDecodeError:
print "Could not resolve " + os.path.join(direc, entry.name)
continue
if not os.path.exists(base):
return
else:
find_in_dir_subdir(base)
return hits
Он возвращает список со всеми путями, указывающими на файлы в списке имен файлов. Использование:
find("C:\\", ["file1.abc", "file2.abc", "file3.abc", "file4.abc", "file5.abc"])
Ответ 4
Для быстрого, независимого от ОС поиска, используйте scandir
https://github.com/benhoyt/scandir/#readme
Подробнее читайте http://bugs.python.org/issue11406.
Ответ 5
Если вы используете Python на Ubuntu, и вы хотите, чтобы он работал на Ubuntu, гораздо более быстрый способ - использовать программу терминала locate
, как это.
import subprocess
def find_files(file_name):
command = ['locate', file_name]
output = subprocess.Popen(command, stdout=subprocess.PIPE).communicate()[0]
output = output.decode()
search_results = output.split('\n')
return search_results
search_results
является list
абсолютных путей к файлу. Это в 10 000 раз быстрее, чем методы выше, и для одного найденного мной поиска это было в 72 000 раз быстрее.
Ответ 6
В Python 3.4 или новее вы можете использовать pathlib для рекурсивного сглаживания:
>>> import pathlib
>>> sorted(pathlib.Path('.').glob('**/*.py'))
[PosixPath('build/lib/pathlib.py'),
PosixPath('docs/conf.py'),
PosixPath('pathlib.py'),
PosixPath('setup.py'),
PosixPath('test_pathlib.py')]
Ссылка: https://docs.python.org/3/library/pathlib.html#pathlib.Path.glob
В Python 3.5 или новее вы также можете сделать рекурсивное сглаживание следующим образом:
>>> import glob
>>> glob.glob('**/*.txt', recursive=True)
['2.txt', 'sub/3.txt']
Ссылка: https://docs.python.org/3/library/glob.html#glob.glob
Ответ 7
Смотрите os module для os.walk или os.listdir
См. также этот вопрос os.walk без копания в каталогах ниже для примера кода
Ответ 8
Ниже мы используем логический "первый" аргумент для переключения между первым совпадением и всеми совпадениями (по умолчанию это эквивалентно "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
Ответ 9
Тогда как найти в Py3.7 все файлы (например,.gif) в папке, но KEYWORD находится в середине имени, например xxxKEYWORDxxxx.gif, ключевое слово начинается с 5 элементов.