Điều này dường như là giải pháp nhanh nhất tôi có thể nghĩ ra, và là nhanh hơn os.walk
và nhanh hơn rất nhiều so với bất kỳ glob
giải pháp .
- Nó cũng sẽ cung cấp cho bạn danh sách tất cả các thư mục con lồng nhau về cơ bản mà không mất phí.
- Bạn có thể tìm kiếm một số tiện ích mở rộng khác nhau.
- Bạn cũng có thể chọn trả về đường dẫn đầy đủ hoặc chỉ tên cho các tệp bằng cách thay đổi
f.path
thành f.name
(không thay đổi nó cho các thư mục con!).
Args: dir: str, ext: list
.
Hàm trả về hai danh sách:subfolders, files
.
Xem bên dưới để biết chi tiết về tốc độ anaylsis.
def run_fast_scandir(dir, ext): # dir: str, ext: list
subfolders, files = [], []
for f in os.scandir(dir):
if f.is_dir():
subfolders.append(f.path)
if f.is_file():
if os.path.splitext(f.name)[1].lower() in ext:
files.append(f.path)
for dir in list(subfolders):
sf, f = run_fast_scandir(dir, ext)
subfolders.extend(sf)
files.extend(f)
return subfolders, files
subfolders, files = run_fast_scandir(folder, [".jpg"])
Phân tích tốc độ
cho các phương pháp khác nhau để lấy tất cả các tệp có phần mở rộng tệp cụ thể bên trong tất cả các thư mục con và thư mục chính.
tl; dr:
- fast_scandir
rõ ràng thắng và nhanh gấp đôi so với tất cả các giải pháp khác, ngoại trừ os.walk.
- os.walk
là vị trí thứ hai chậm hơn rất nhiều.
- sử dụng glob
sẽ làm chậm quá trình.
- Không có kết quả nào sử dụng sắp xếp tự nhiên . Điều này có nghĩa là các kết quả sẽ được sắp xếp như sau: 1, 10, 2. Để có được sắp xếp tự nhiên (1, 2, 10), vui lòng xem tại https://stackoverflow.com/a/48030307/2441026
Các kết quả:
fast_scandir took 499 ms. Found files: 16596. Found subfolders: 439
os.walk took 589 ms. Found files: 16596
find_files took 919 ms. Found files: 16596
glob.iglob took 998 ms. Found files: 16596
glob.glob took 1002 ms. Found files: 16596
pathlib.rglob took 1041 ms. Found files: 16596
os.walk-glob took 1043 ms. Found files: 16596
Các thử nghiệm được thực hiện với W7x64, Python 3.8.1, 20 lần chạy. 16596 tệp trong 439 thư mục con (lồng nhau một phần).
find_files
là từ https://stackoverflow.com/a/45646357/2441026 và cho phép bạn tìm kiếm một số tiện ích mở rộng.
fast_scandir
do chính tôi viết và cũng sẽ trả về một danh sách các thư mục con. Bạn có thể cung cấp cho nó một danh sách các tiện ích mở rộng để tìm kiếm (Tôi đã thử nghiệm một danh sách với một mục nhập đơn giản if ... == ".jpg"
và không có sự khác biệt đáng kể).
# -*- coding: utf-8 -*-
# Python 3
import time
import os
from glob import glob, iglob
from pathlib import Path
directory = r"<folder>"
RUNS = 20
def run_os_walk():
a = time.time_ns()
for i in range(RUNS):
fu = [os.path.join(dp, f) for dp, dn, filenames in os.walk(directory) for f in filenames if
os.path.splitext(f)[1].lower() == '.jpg']
print(f"os.walk\t\t\ttook {(time.time_ns() - a) / 1000 / 1000 / RUNS:.0f} ms. Found files: {len(fu)}")
def run_os_walk_glob():
a = time.time_ns()
for i in range(RUNS):
fu = [y for x in os.walk(directory) for y in glob(os.path.join(x[0], '*.jpg'))]
print(f"os.walk-glob\ttook {(time.time_ns() - a) / 1000 / 1000 / RUNS:.0f} ms. Found files: {len(fu)}")
def run_glob():
a = time.time_ns()
for i in range(RUNS):
fu = glob(os.path.join(directory, '**', '*.jpg'), recursive=True)
print(f"glob.glob\t\ttook {(time.time_ns() - a) / 1000 / 1000 / RUNS:.0f} ms. Found files: {len(fu)}")
def run_iglob():
a = time.time_ns()
for i in range(RUNS):
fu = list(iglob(os.path.join(directory, '**', '*.jpg'), recursive=True))
print(f"glob.iglob\t\ttook {(time.time_ns() - a) / 1000 / 1000 / RUNS:.0f} ms. Found files: {len(fu)}")
def run_pathlib_rglob():
a = time.time_ns()
for i in range(RUNS):
fu = list(Path(directory).rglob("*.jpg"))
print(f"pathlib.rglob\ttook {(time.time_ns() - a) / 1000 / 1000 / RUNS:.0f} ms. Found files: {len(fu)}")
def find_files(files, dirs=[], extensions=[]):
# https://stackoverflow.com/a/45646357/2441026
new_dirs = []
for d in dirs:
try:
new_dirs += [ os.path.join(d, f) for f in os.listdir(d) ]
except OSError:
if os.path.splitext(d)[1].lower() in extensions:
files.append(d)
if new_dirs:
find_files(files, new_dirs, extensions )
else:
return
def run_fast_scandir(dir, ext): # dir: str, ext: list
# https://stackoverflow.com/a/59803793/2441026
subfolders, files = [], []
for f in os.scandir(dir):
if f.is_dir():
subfolders.append(f.path)
if f.is_file():
if os.path.splitext(f.name)[1].lower() in ext:
files.append(f.path)
for dir in list(subfolders):
sf, f = run_fast_scandir(dir, ext)
subfolders.extend(sf)
files.extend(f)
return subfolders, files
if __name__ == '__main__':
run_os_walk()
run_os_walk_glob()
run_glob()
run_iglob()
run_pathlib_rglob()
a = time.time_ns()
for i in range(RUNS):
files = []
find_files(files, dirs=[directory], extensions=[".jpg"])
print(f"find_files\t\ttook {(time.time_ns() - a) / 1000 / 1000 / RUNS:.0f} ms. Found files: {len(files)}")
a = time.time_ns()
for i in range(RUNS):
subf, files = run_fast_scandir(directory, [".jpg"])
print(f"fast_scandir\ttook {(time.time_ns() - a) / 1000 / 1000 / RUNS:.0f} ms. Found files: {len(files)}. Found subfolders: {len(subf)}")