Tôi có một tệp có thể ở một nơi khác trên máy của mỗi người dùng. Có cách nào để thực hiện tìm kiếm tệp không? Một cách để tôi có thể chuyển tên tệp và cây thư mục để tìm kiếm?
Tôi có một tệp có thể ở một nơi khác trên máy của mỗi người dùng. Có cách nào để thực hiện tìm kiếm tệp không? Một cách để tôi có thể chuyển tên tệp và cây thư mục để tìm kiếm?
Câu trả lời:
os.walk là câu trả lời, điều này sẽ tìm thấy kết quả phù hợp đầu tiên:
import os
def find(name, path):
for root, dirs, files in os.walk(path):
if name in files:
return os.path.join(root, name)
Và điều này sẽ tìm thấy tất cả các trận đấu:
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
Và điều này sẽ phù hợp với một mẫu:
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:sẽ không tìm kiếm được super-photo.jpgkhi nó super-photo.JPGnằm trong hệ thống tệp. (một giờ trong đời, tôi muốn quay lại ;-) Cách sửa chữa hơi lộn xộn làif str.lower(name) in [x.lower() for x in files]
Tôi đã sử dụng phiên bản của os.walkvà trên một thư mục lớn hơn có thời gian khoảng 3,5 giây. Tôi đã thử hai giải pháp ngẫu nhiên mà không có cải tiến lớn, sau đó chỉ làm:
paths = [line[2:] for line in subprocess.check_output("find . -iname '*.txt'", shell=True).splitlines()]
Trong khi nó chỉ dành cho POSIX, tôi đã có 0,25 giây.
Từ điều này, tôi tin rằng hoàn toàn có thể tối ưu hóa toàn bộ tìm kiếm theo cách độc lập với nền tảng, nhưng đây là lúc tôi dừng nghiên cứu.
Nếu bạn đang sử dụng Python trên Ubuntu và bạn chỉ muốn nó hoạt động trên Ubuntu thì một cách nhanh hơn đáng kể là sử dụng locatechương trình của thiết bị đầu cuối như thế này.
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_resultslà một listtrong những đường dẫn tệp tuyệt đối. Cách này nhanh hơn 10.000 lần so với các phương pháp trên và đối với một lần tìm kiếm tôi đã thực hiện nhanh hơn ~ 72.000 lần.
Trong Python 3.4 hoặc mới hơn, bạn có thể sử dụng pathlib để thực hiện thao tác lặp lại đệ quy:
>>> 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')]
Tham khảo: https://docs.python.org/3/library/pathlib.html#pathlib.Path.glob
Trong Python 3.5 hoặc mới hơn, bạn cũng có thể thực hiện thao tác lặp lại đệ quy như sau:
>>> import glob
>>> glob.glob('**/*.txt', recursive=True)
['2.txt', 'sub/3.txt']
Tham khảo: https://docs.python.org/3/library/glob.html#glob.glob
Để tìm kiếm nhanh chóng, không phụ thuộc vào hệ điều hành, hãy sử dụng scandir
https://github.com/benhoyt/scandir/#readme
Đọc http://bugs.python.org/issue11406 để biết chi tiết tại sao.
Nếu bạn đang làm việc với Python 2, bạn gặp sự cố với đệ quy vô hạn trên các cửa sổ do các liên kết tượng trưng tự giới thiệu.
Tập lệnh này sẽ tránh làm theo những điều đó. Lưu ý rằng đây là cửa sổ cụ thể !
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
Nó trả về một danh sách với tất cả các đường dẫn trỏ đến các tệp trong danh sách tên tệp. Sử dụng:
find("C:\\", ["file1.abc", "file2.abc", "file3.abc", "file4.abc", "file5.abc"])
Dưới đây chúng tôi sử dụng đối số boolean "đầu tiên" để chuyển đổi giữa kết hợp đầu tiên và tất cả các kết quả phù hợp (mặc định tương đương với "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
Câu trả lời rất giống với những cái hiện có, nhưng được tối ưu hóa một chút.
Vì vậy, bạn có thể tìm thấy bất kỳ tệp hoặc thư mục nào theo mẫu:
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)
)
hoặc bằng chuỗi con:
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
)
hoặc sử dụng một vị ngữ:
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)
)
để chỉ tìm kiếm tệp hoặc chỉ thư mục - thay thế “dirs + tệp”, ví dụ: chỉ bằng “dirs” hoặc chỉ “tệp”, tùy thuộc vào những gì bạn cần.
Trân trọng.
Câu trả lời của SARose đã phù hợp với tôi cho đến khi tôi cập nhật từ Ubuntu 20.04 LTS. Thay đổi nhỏ mà tôi đã thực hiện đối với mã của anh ấy khiến nó hoạt động trên bản phát hành Ubuntu mới nhất.
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