Procurar um ficheiro em python

Tenho um ficheiro que pode estar num lugar diferente na máquina de cada utilizador. Existe uma maneira de implementar uma busca para o arquivo? Uma forma de passar o nome do ficheiro e a árvore de directórios para procurar?

 66
Author: directedition, 2009-11-12

7 answers

Os.walk é a resposta, isto vai encontrar o primeiro jogo:

import os

def find(name, path):
    for root, dirs, files in os.walk(path):
        if name in files:
            return os.path.join(root, name)

E isto irá encontrar todas as correspondências:

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

E isto irá corresponder a um padrão:

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')
 161
Author: Nadia Alramli, 2009-11-12 19:33:17

Eu usei uma versão de os.walk e em um diretório maior tem tempos em torno de 3,5 segundos. eu tentei duas soluções aleatórias sem grande melhoria, então apenas fez:

paths = [line[2:] for line in subprocess.check_output("find . -iname '*.txt'", shell=True).splitlines()]
Enquanto É só POSIX, tenho 0,25 segundos. A partir disto, acredito que é inteiramente possível otimizar toda a busca de uma forma independente da plataforma, mas foi aqui que interrompi a pesquisa.
 15
Author: kgadek, 2014-07-10 15:00:13

Se está a trabalhar com o Python 2, tem um problema com a recursão infinita nas janelas causada por ligações simbólicas auto-referenciadas.

Este script evitará segui-los. Note que este é O windows-specific !

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

Devolve uma lista com todas as localizações que apontam para ficheiros na lista de nomes de ficheiros. Utilização:

find("C:\\", ["file1.abc", "file2.abc", "file3.abc", "file4.abc", "file5.abc"])
 4
Author: F.M.F., 2017-11-30 21:08:13

Para pesquisa rápida e independente do sistema operacional, usar scandir

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

Leia http://bugs.python.org/issue11406 {[6] } para mais pormenores, porquê.

 2
Author: Dima Tisnek, 2014-06-19 09:36:07

Ver o módulopara os.andar ou So.listdir

Ver também esta questão os.caminhe sem escavar as pastas abaixo de para obter o código da amostra

 1
Author: Martin Beckett, 2017-05-23 12:18:10

Se estiver a usar Python no Ubuntu e só quiser que ele funcione no Ubuntu de uma forma substancialmente mais rápida é usar o programa do terminal locate como este.

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 é um list dos caminhos absolutos dos ficheiros. Isto é 10.000 vezes mais rápido do que os métodos acima e para uma pesquisa que eu fiz foi ~72.000 vezes mais rápido.

 1
Author: SARose, 2017-02-02 15:16:03

No Python 3. 4 ou mais recente pode usar a pathlib para fazer a globulação recursiva:

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

Referência: https://docs.python.org/3/library/pathlib.html#pathlib.Path.glob

No Python 3.5 ou mais recente, também pode fazer globulação recursiva como esta:

>>> import glob
>>> glob.glob('**/*.txt', recursive=True)
['2.txt', 'sub/3.txt']

Referência: https://docs.python.org/3/library/glob.html#glob.glob

 1
Author: Kenyon, 2018-06-29 05:27:30