Найти файл в python



У меня есть файл, который может быть в другое место на компьютере каждого пользователя. Есть ли способ реализовать поиск файла? Так что я могу передать имя файла и дерево каталогов для поиска?

362   7  

7 ответов:

ОС.гуляй это ответ, это будет найти первый матч:

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')

я использовал версию os.walk и в большем каталоге есть время около 3,5 сек. Я пробовал два случайных решений не большое улучшение, потом просто делал так:

paths = [line[2:] for line in subprocess.check_output("find . -iname '*.txt'", shell=True).splitlines()]

пока это только POSIX, я получил 0,25 сек.

из этого я считаю, что вполне возможно оптимизировать весь поиск много независимым от платформы способом, но именно здесь я остановил исследование.

Если вы работаете с 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 = 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"])

для быстрого, независимого от ОС поиска, используйте scandir

https://github.com/benhoyt/scandir/#readme

Читать http://bugs.python.org/issue11406 подробнее почему.

посмотреть модуль ОС для ОС.прогулка или ОС.listdir

Смотрите также этот вопрос оС.ходите не копаясь в каталогах ниже пример кода

если вы используете 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 раз быстрее.

в 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

Comments

    Ничего не найдено.