Tenho um arquivo que pode estar em um local diferente na máquina de cada usuário. Existe uma maneira de implementar uma pesquisa para o arquivo? Uma forma de passar o nome do arquivo e a árvore de diretórios a pesquisar?
os.walk é a resposta, ele encontrará a primeira correspondência:
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 isso 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 isso vai 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')
Observe que esses exemplos encontrarão apenas arquivos, não diretórios com o mesmo nome. Se você quiser encontrar qualquer objeto no diretório com esse nome, você pode usarif name in file or name in dirs
Mark E. Hamilton
9
Tenha cuidado com a distinção entre maiúsculas e minúsculas. for name in files:falhará ao procurar super-photo.jpgquando está super-photo.JPGno sistema de arquivos. (uma hora da minha vida que eu gostaria de voltar ;-) Solução um pouco complicada éif str.lower(name) in [x.lower() for x in files]
matt wilkie
Que tal usar o rendimento em vez de preparar a lista de resultados? ..... if fnmatch.fnmatch (nome, padrão): rendimento os.path.join (raiz, nome)
Berci
Considere atualizar sua resposta às primitivas do Python 3.x
Dima Tisnek
1
A lista de compreensão pode substituir a função, por exemplo, find_all: res = [os.path.join (root, nome) para root, dirs, arquivos em os.walk (caminho) se o nome nos arquivos]
Nir
23
Usei uma versão de os.walke em um diretório maior, com tempos em torno de 3,5 segundos. Tentei duas soluções aleatórias sem grandes melhorias, mas fiz:
paths =[line[2:]for line in subprocess.check_output("find . -iname '*.txt'", shell=True).splitlines()]
Embora seja apenas POSIX, eu tenho 0,25 seg.
A partir disso, acredito que seja inteiramente possível otimizar bastante a busca inteira de forma independente da plataforma, mas foi aí que parei a pesquisa.
Se você está usando Python no Ubuntu e deseja que ele funcione apenas no Ubuntu, uma forma substancialmente mais rápida é usar o locateprograma do terminal desta forma.
search_resultsé um listdos caminhos de arquivo absolutos. Isso é 10.000 vezes mais rápido do que os métodos acima e, para uma pesquisa que fiz, foi aproximadamente 72.000 vezes mais rápido.
Especificamente, use scandir.walk()a resposta de @Nadia. Observe que se você estiver usando o Python 3.5+, os.walk()já tem os scandir.walk()aceleradores. Além disso, o PEP 471 é provavelmente um documento melhor para ler informações do que esse problema.
Ben Hoyt
3
Se você estiver trabalhando com Python 2, terá um problema com a recursão infinita em janelas causada por links simbólicos autorreferidos.
Este script evitará seguir aqueles. Observe que isso é específico do 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
Ele retorna uma lista com todos os caminhos que apontam para arquivos na lista de nomes de arquivos. Uso:
A seguir, usamos um argumento booleano "primeiro" para alternar entre a primeira correspondência e todas as correspondências (um padrão que é equivalente a "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
A resposta é muito semelhante às existentes, mas ligeiramente otimizada.
Assim, você pode encontrar qualquer arquivo ou pasta por padrão:
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))
quer por substring:
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
)
ou usando um predicado:
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))
para pesquisar apenas arquivos ou apenas pastas - substitua “dirs + arquivos”, por exemplo, por apenas “dirs” ou apenas “arquivos”, dependendo do que você precisa.
A resposta de SARose funcionou para mim até que eu atualizei do Ubuntu 20.04 LTS. A ligeira mudança que fiz em seu código o faz funcionar na versão mais recente do Ubuntu.
Respostas:
os.walk é a resposta, ele encontrará a primeira correspondência:
E isso encontrará todas as correspondências:
E isso vai corresponder a um padrão:
fonte
if name in file or name in dirs
for name in files:
falhará ao procurarsuper-photo.jpg
quando estásuper-photo.JPG
no sistema de arquivos. (uma hora da minha vida que eu gostaria de voltar ;-) Solução um pouco complicada éif str.lower(name) in [x.lower() for x in files]
Usei uma versão de
os.walk
e em um diretório maior, com tempos em torno de 3,5 segundos. Tentei duas soluções aleatórias sem grandes melhorias, mas fiz:Embora seja apenas POSIX, eu tenho 0,25 seg.
A partir disso, acredito que seja inteiramente possível otimizar bastante a busca inteira de forma independente da plataforma, mas foi aí que parei a pesquisa.
fonte
Se você está usando Python no Ubuntu e deseja que ele funcione apenas no Ubuntu, uma forma substancialmente mais rápida é usar o
locate
programa do terminal desta forma.search_results
é umlist
dos caminhos de arquivo absolutos. Isso é 10.000 vezes mais rápido do que os métodos acima e, para uma pesquisa que fiz, foi aproximadamente 72.000 vezes mais rápido.fonte
No Python 3.4 ou mais recente, você pode usar pathlib para fazer globbing recursivo:
Referência: https://docs.python.org/3/library/pathlib.html#pathlib.Path.glob
No Python 3.5 ou mais recente, você também pode fazer globbing recursivo como este:
Referência: https://docs.python.org/3/library/glob.html#glob.glob
fonte
Para uma pesquisa rápida e independente do sistema operacional, use
scandir
https://github.com/benhoyt/scandir/#readme
Leia http://bugs.python.org/issue11406 para obter detalhes sobre o motivo.
fonte
scandir.walk()
a resposta de @Nadia. Observe que se você estiver usando o Python 3.5+,os.walk()
já tem osscandir.walk()
aceleradores. Além disso, o PEP 471 é provavelmente um documento melhor para ler informações do que esse problema.Se você estiver trabalhando com Python 2, terá um problema com a recursão infinita em janelas causada por links simbólicos autorreferidos.
Este script evitará seguir aqueles. Observe que isso é específico do Windows !
Ele retorna uma lista com todos os caminhos que apontam para arquivos na lista de nomes de arquivos. Uso:
fonte
A seguir, usamos um argumento booleano "primeiro" para alternar entre a primeira correspondência e todas as correspondências (um padrão que é equivalente a "find. -Name file"):
fonte
A resposta é muito semelhante às existentes, mas ligeiramente otimizada.
Assim, você pode encontrar qualquer arquivo ou pasta por padrão:
quer por substring:
ou usando um predicado:
para pesquisar apenas arquivos ou apenas pastas - substitua “dirs + arquivos”, por exemplo, por apenas “dirs” ou apenas “arquivos”, dependendo do que você precisa.
Saudações.
fonte
A resposta de SARose funcionou para mim até que eu atualizei do Ubuntu 20.04 LTS. A ligeira mudança que fiz em seu código o faz funcionar na versão mais recente do Ubuntu.
fonte