Her kullanıcının makinesinde farklı bir yerde olabilecek bir dosyam var. Dosya için arama yapmanın bir yolu var mı? Dosyanın adını ve arama yapmak için dizin ağacını iletebilmemin bir yolu?
Her kullanıcının makinesinde farklı bir yerde olabilecek bir dosyam var. Dosya için arama yapmanın bir yolu var mı? Dosyanın adını ve arama yapmak için dizin ağacını iletebilmemin bir yolu?
Yanıtlar:
os.walk cevaptır, bu ilk eşleşmeyi bulacaktır:
import os
def find(name, path):
for root, dirs, files in os.walk(path):
if name in files:
return os.path.join(root, name)
Ve bu, tüm eşleşmeleri bulacaktır:
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
Ve bu bir kalıpla eşleşecek:
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')
if name in file or name in dirs
for name in files:arayan başarısız olur super-photo.jpgo geldiğinde super-photo.JPGdosya sisteminde. (hayatımın bir saatini geri istiyorum ;-) Biraz dağınık bir düzeltmeif str.lower(name) in [x.lower() for x in files]
Daha os.walkbüyük bir dizinin bir sürümünü kullandım ve 3.5 saniye civarında süreler aldım. Büyük bir gelişme olmadan iki rastgele çözüm denedim, sonra şimdi yaptım:
paths = [line[2:] for line in subprocess.check_output("find . -iname '*.txt'", shell=True).splitlines()]
Yalnızca POSIX olsa da 0.25 saniyem var.
Buradan, tüm aramayı platformdan bağımsız bir şekilde optimize etmenin tamamen mümkün olduğuna inanıyorum, ancak araştırmayı burada durdurdum.
Ubuntu üzerinde Python kullanıyorsanız ve sadece Ubuntu üzerinde çalışmasını istiyorsanız, çok daha hızlı bir yol, terminalin locateprogramını bu şekilde kullanmaktır .
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_resultsa, listmutlak dosya yollarının. Bu, yukarıdaki yöntemlerden 10.000 kat daha hızlı ve yaptığım bir arama için ~ 72.000 kat daha hızlıydı.
Python 3.4 veya daha yenisinde, özyinelemeli genelleme yapmak için pathlib'i kullanabilirsiniz:
>>> 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')]
Referans: https://docs.python.org/3/library/pathlib.html#pathlib.Path.glob
Python 3.5 veya daha yeni sürümlerde, aşağıdaki gibi yinelemeli genelleme de yapabilirsiniz:
>>> import glob
>>> glob.glob('**/*.txt', recursive=True)
['2.txt', 'sub/3.txt']
Referans: https://docs.python.org/3/library/glob.html#glob.glob
Hızlı, işletim sisteminden bağımsız arama için kullanın scandir
https://github.com/benhoyt/scandir/#readme
Nedeniyle ilgili ayrıntılar için http://bugs.python.org/issue11406 okuyun .
Python 2 ile çalışıyorsanız, kendine atıfta bulunan sembolik bağların neden olduğu pencerelerde sonsuz özyineleme ile ilgili bir sorununuz var.
Bu komut dosyası, bunları takip etmekten kaçınacaktır. Bunun pencerelere özgü olduğunu unutmayın !
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
Dosya adları listesindeki dosyalara işaret eden tüm yolları içeren bir liste döndürür. Kullanım:
find("C:\\", ["file1.abc", "file2.abc", "file3.abc", "file4.abc", "file5.abc"])
Aşağıda, ilk eşleşme ve tüm eşleşmeler arasında geçiş yapmak için bir boole "ilk" bağımsız değişkeni kullanıyoruz (". -Adı dosyası bul" ile eşdeğer bir varsayılan):
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
Cevap, mevcut olanlara çok benzer, ancak biraz optimize edilmiştir.
Böylece herhangi bir dosya veya klasörü kalıba göre bulabilirsiniz:
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)
)
alt dize ile:
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
)
veya bir yüklem kullanarak:
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)
)
yalnızca dosyaları veya yalnızca klasörleri aramak için - örneğin, neye ihtiyacınız olduğuna bağlı olarak "dirs + files" yerine yalnızca "dirs" veya yalnızca "files" yazın.
Saygılarımızla.
SARose'un cevabı, Ubuntu 20.04 LTS'den güncelleme yapana kadar benim için çalıştı. Kodunda yaptığım küçük değişiklik, onu en son Ubuntu sürümünde çalışmasını sağlıyor.
import subprocess
def find_files(file_name):
file_name = 'chromedriver'
command = ['locate'+ ' ' + file_name]
output = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True).communicate()[0]
output = output.decode()
search_results = output.split('\n')
return search_results