Procurar um ficheiro em python
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')
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.
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"])
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ê.
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
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.
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