Saya memiliki file yang mungkin berada di tempat yang berbeda pada mesin setiap pengguna. Apakah ada cara untuk mengimplementasikan pencarian file? Sebuah cara agar saya dapat mengirimkan nama file dan pohon direktori untuk mencari?
Saya memiliki file yang mungkin berada di tempat yang berbeda pada mesin setiap pengguna. Apakah ada cara untuk mengimplementasikan pencarian file? Sebuah cara agar saya dapat mengirimkan nama file dan pohon direktori untuk mencari?
Jawaban:
os.walk adalah jawabannya, ini akan menemukan pertandingan pertama:
import os
def find(name, path):
for root, dirs, files in os.walk(path):
if name in files:
return os.path.join(root, name)
Dan ini akan menemukan semua kecocokan:
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
Dan ini akan cocok dengan pola:
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:akan gagal mencari super-photo.jpgsaat berada super-photo.JPGdi sistem file. (satu jam dalam hidup saya, saya ingin kembali ;-) Perbaikan yang agak berantakan adalahif str.lower(name) in [x.lower() for x in files]
Saya menggunakan versi os.walkdan pada direktori yang lebih besar mendapat waktu sekitar 3,5 detik. Saya mencoba dua solusi acak tanpa peningkatan yang berarti, lalu baru saja melakukannya:
paths = [line[2:] for line in subprocess.check_output("find . -iname '*.txt'", shell=True).splitlines()]
Meskipun hanya untuk POSIX, saya mendapat 0,25 detik.
Dari sini, saya yakin sangat mungkin untuk banyak mengoptimalkan pencarian secara keseluruhan dengan cara yang tidak bergantung platform, tetapi di sinilah saya menghentikan penelitian.
Jika Anda menggunakan Python di Ubuntu dan Anda hanya ingin Python bekerja di Ubuntu, cara yang jauh lebih cepat adalah menggunakan program terminal locateseperti ini.
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_resultsadalah salah listsatu jalur file absolut. Ini 10.000 kali lebih cepat daripada metode di atas dan untuk satu pencarian yang saya lakukan ~ 72.000 kali lebih cepat.
Di Python 3.4 atau yang lebih baru, Anda dapat menggunakan pathlib untuk melakukan globbing rekursif:
>>> 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')]
Referensi: https://docs.python.org/3/library/pathlib.html#pathlib.Path.glob
Di Python 3.5 atau yang lebih baru, Anda juga dapat melakukan globbing rekursif seperti ini:
>>> import glob
>>> glob.glob('**/*.txt', recursive=True)
['2.txt', 'sub/3.txt']
Referensi: https://docs.python.org/3/library/glob.html#glob.glob
Untuk pencarian cepat dan tidak tergantung OS, gunakan scandir
https://github.com/benhoyt/scandir/#readme
Baca http://bugs.python.org/issue11406 untuk detail alasannya.
Jika Anda bekerja dengan Python 2, Anda memiliki masalah dengan rekursi tak terbatas pada windows yang disebabkan oleh symlink yang merujuk sendiri.
Skrip ini akan menghindari mengikuti itu. Perhatikan bahwa ini khusus untuk jendela !
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
Ini mengembalikan daftar dengan semua jalur yang mengarah ke file dalam daftar nama file. Pemakaian:
find("C:\\", ["file1.abc", "file2.abc", "file3.abc", "file4.abc", "file5.abc"])
Di bawah ini kami menggunakan argumen boolean "pertama" untuk beralih antara kecocokan pertama dan semua kecocokan (default yang setara dengan "temukan. -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
Jawabannya sangat mirip dengan yang sudah ada, tetapi sedikit dioptimalkan.
Jadi Anda dapat menemukan file atau folder apa pun berdasarkan pola:
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)
)
baik dengan 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
)
atau menggunakan predikat:
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)
)
untuk mencari hanya file atau folder saja - ganti “dirs + files”, misalnya, dengan hanya “dirs” atau hanya “files”, tergantung pada apa yang Anda butuhkan.
Salam.
Jawaban SARose berfungsi untuk saya sampai saya memperbarui dari Ubuntu 20.04 LTS. Sedikit perubahan yang saya buat pada kodenya membuatnya berfungsi pada rilis Ubuntu terbaru.
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