Lấy danh sách các tập tin được lọc trong một thư mục


281

Tôi đang cố gắng để có được một danh sách các tệp trong một thư mục bằng Python, nhưng tôi không muốn một danh sách TẤT CẢ các tệp.

Điều tôi thực sự muốn là khả năng làm một cái gì đó như sau nhưng sử dụng Python và không thực thi ls.

ls 145592*.jpg

Nếu không có phương thức tích hợp cho việc này, tôi hiện đang nghĩ đến việc viết một vòng lặp for để lặp qua kết quả của một os.listdir()và để thêm tất cả các tệp phù hợp vào một danh sách mới.

Tuy nhiên, có rất nhiều tệp trong thư mục đó và do đó tôi hy vọng có một phương pháp hiệu quả hơn (hoặc một phương thức tích hợp).


[Liên kết này có thể giúp bạn :) Nhận danh sách các tệp được lọc trong một thư mục] ( codereview.stackexchange.com/a/33642 )
sha111

Lưu ý rằng bạn có thể đặc biệt quan tâm đến việc sắp xếp thứ tự nếu điều này quan trọng cho ứng dụng của bạn.
thắt lưng

Câu trả lời:


385

21
Ồ, tôi chỉ nhận thấy rằng các tài liệu Python nói global () "được thực hiện bằng cách sử dụng các hàm os.listdir () và fnmatch.fnmatch () trong buổi hòa nhạc, chứ không phải bằng cách thực sự gọi một subshell". Nói cách khác, global () không có những cải tiến hiệu quả mà người ta có thể mong đợi.
Ben Hoyt

5
Có một sự khác biệt chính: glob.glob('145592*.jpg')in toàn bộ đường dẫn tuyệt đối của tệp trong khi ls 145592*.jpgchỉ in danh sách tệp.
Ébe Isaac

8
@Ben Tại sao việc gọi một subshell (quy trình con) có bất kỳ cải tiến hiệu quả?
Paulo Neves

7
@PauloNeves: đúng, nhận xét của tôi ở trên cũng không có ý nghĩa với tôi 7 năm sau. :-) Tôi đoán rằng tôi đã đề cập đến thực tế là glob()chỉ sử dụng listdir + fnmatch, thay vì các cuộc gọi hệ điều hành đặc biệt để thực hiện lọc ký tự đại diện. Ví dụ: trên Windows, FindFirstFileAPI cho phép bạn chỉ định các ký tự đại diện để HĐH thực hiện quá trình lọc trực tiếp và có lẽ hiệu quả hơn (tôi không nghĩ có tương đương trên Linux).
Ben Hoyt

1
@marsh: Như mọi khi, thư mục làm việc hiện tại của quá trình.
Ignacio Vazquez-Abrams

124

glob.glob()chắc chắn là cách để làm điều đó (theo Ignacio). Tuy nhiên, nếu bạn cần kết hợp phức tạp hơn, bạn có thể thực hiện điều đó với sự hiểu biết danh sách và re.match(), đại loại như vậy:

files = [f for f in os.listdir('.') if re.match(r'[0-9]+.*\.jpg', f)]

Linh hoạt hơn, nhưng như bạn lưu ý, kém hiệu quả.


Điều này chắc chắn dường như mạnh mẽ hơn. Ví dụ: phải làm một cái gì đó như[0-9]+
demongolem

3
Vâng, chắc chắn là mạnh hơn - tuy nhiên fnmatch không hỗ trợ [0123456789]các chuỗi ( xem tài liệu ) và nó cũng có fnmatch.filter()chức năng làm cho vòng lặp này hiệu quả hơn một chút.
Ben Hoyt

49

Giữ cho nó đơn giản:

import os
relevant_path = "[path to folder]"
included_extensions = ['jpg','jpeg', 'bmp', 'png', 'gif']
file_names = [fn for fn in os.listdir(relevant_path)
              if any(fn.endswith(ext) for ext in included_extensions)]

Tôi thích hình thức hiểu danh sách này vì nó đọc tốt bằng tiếng Anh.

Tôi đọc dòng thứ tư là: Đối với mỗi fn trong os.listdir cho đường dẫn của tôi, chỉ cung cấp cho tôi những dòng phù hợp với bất kỳ tiện ích mở rộng nào trong số các tiện ích mở rộng của tôi.

Các lập trình viên python mới làm quen có thể thực sự quen với việc sử dụng tính năng hiểu danh sách để lọc và nó có thể có một số chi phí bộ nhớ cho các tập dữ liệu rất lớn, nhưng để liệt kê một thư mục và các tác vụ lọc chuỗi đơn giản khác, việc hiểu danh sách sẽ dễ dàng hơn mã tài liệu.

Điều duy nhất về thiết kế này là nó không bảo vệ bạn khỏi việc mắc sai lầm khi truyền chuỗi thay vì danh sách. Ví dụ: nếu bạn vô tình chuyển đổi một chuỗi thành một danh sách và cuối cùng kiểm tra tất cả các ký tự của một chuỗi, cuối cùng bạn có thể nhận được một loạt các thông báo sai.

Nhưng tốt hơn là có một vấn đề dễ khắc phục hơn là một giải pháp khó hiểu.


5
Không phải là có bất kỳ nhu cầu nào any()ở đây, bởi vì str.endswith()có một chuỗi kết thúc. if fn.endswith(included_extentensions)là quá đủ
Martijn Pieters

3
Ngoài việc không sử dụng str.endswith(seq)mà Martijn đã chỉ ra, điều này là không chính xác, bởi vì một tệp phải kết thúc với .extnó để có phần mở rộng đó. Mã này cũng sẽ tìm thấy (ví dụ) một tệp có tên "myjpg" hoặc một thư mục có tên chỉ là "png". Để khắc phục, chỉ cần thêm tiền tố vào mỗi phần mở rộng included_extensionsbằng a ..
Ben Hoyt

Tôi luôn cảnh giác một chút về mã trong các câu trả lời rõ ràng là không được chạy hoặc không thể chạy. Biến included_extensionsvs included_extentsions? Thật đáng tiếc vì nếu không đây là câu trả lời ưa thích của tôi.
Auspice


17

Bộ lọc với globmô-đun:

Nhập khẩu toàn cầu

import glob

Thẻ hoang dã:

files=glob.glob("data/*")
print(files)

Out:

['data/ks_10000_0', 'data/ks_1000_0', 'data/ks_100_0', 'data/ks_100_1',
'data/ks_100_2', 'data/ks_106_0', 'data/ks_19_0', 'data/ks_200_0', 'data/ks_200_1', 
'data/ks_300_0', 'data/ks_30_0', 'data/ks_400_0', 'data/ks_40_0', 'data/ks_45_0', 
'data/ks_4_0', 'data/ks_500_0', 'data/ks_50_0', 'data/ks_50_1', 'data/ks_60_0', 
'data/ks_82_0', 'data/ks_lecture_dp_1', 'data/ks_lecture_dp_2']

Mở rộng Fiter .txt:

files = glob.glob("/home/ach/*/*.txt")

Một nhân vật

glob.glob("/home/ach/file?.txt")

Phạm vi số

glob.glob("/home/ach/*[0-9]*")

Dãy chữ cái

glob.glob("/home/ach/[a-c]*")

12

Mã sơ bộ

import glob
import fnmatch
import pathlib
import os

pattern = '*.py'
path = '.'

Giải pháp 1 - sử dụng "toàn cầu"

# lookup in current dir
glob.glob(pattern)

In [2]: glob.glob(pattern)
Out[2]: ['wsgi.py', 'manage.py', 'tasks.py']

Giải pháp 2 - sử dụng "os" + "fnmatch"

Biến thể 2.1 - Tra cứu trong thư mục hiện tại

# lookup in current dir
fnmatch.filter(os.listdir(path), pattern)

In [3]: fnmatch.filter(os.listdir(path), pattern)
Out[3]: ['wsgi.py', 'manage.py', 'tasks.py']

Biến thể 2.2 - Tra cứu đệ quy

# lookup recursive
for dirpath, dirnames, filenames in os.walk(path):

    if not filenames:
        continue

    pythonic_files = fnmatch.filter(filenames, pattern)
    if pythonic_files:
        for file in pythonic_files:
            print('{}/{}'.format(dirpath, file))

Kết quả

./wsgi.py
./manage.py
./tasks.py
./temp/temp.py
./apps/diaries/urls.py
./apps/diaries/signals.py
./apps/diaries/actions.py
./apps/diaries/querysets.py
./apps/library/tests/test_forms.py
./apps/library/migrations/0001_initial.py
./apps/polls/views.py
./apps/polls/formsets.py
./apps/polls/reports.py
./apps/polls/admin.py

Giải pháp 3 - sử dụng "pathlib"

# lookup in current dir
path_ = pathlib.Path('.')
tuple(path_.glob(pattern))

# lookup recursive
tuple(path_.rglob(pattern))

Ghi chú:

  1. Đã thử nghiệm trên Python 3.4
  2. Mô-đun "pathlib" chỉ được thêm vào trong Python 3.4
  3. Python 3.5 đã thêm một tính năng để tra cứu đệ quy với global.glob https://docs.python.org/3.5/l Library / glob.html # glob.glob . Vì máy của tôi được cài đặt với Python 3.4, tôi chưa kiểm tra điều đó.

9

sử dụng os.walk để liệt kê đệ quy các tệp của bạn

import os
root = "/home"
pattern = "145992"
alist_filter = ['jpg','bmp','png','gif'] 
path=os.path.join(root,"mydir_to_scan")
for r,d,f in os.walk(path):
    for file in f:
        if file[-3:] in alist_filter and pattern in file:
            print os.path.join(root,file)

Không cần phải cắt lát; file.endswith(alist_filter)Là đủ.
Martijn Pieters

5
import os

dir="/path/to/dir"
[x[0]+"/"+f for x in os.walk(dir) for f in x[2] if f.endswith(".jpg")]

Điều này sẽ cung cấp cho bạn một danh sách các tệp jpg với đường dẫn đầy đủ của chúng. Bạn có thể thay thế x[0]+"/"+fbằng fchỉ tên tập tin. Bạn cũng có thể thay thế f.endswith(".jpg")bằng bất kỳ điều kiện chuỗi nào bạn muốn.


3

bạn cũng có thể thích một cách tiếp cận cấp cao hơn (tôi đã triển khai và đóng gói dưới dạng findtools ):

from findtools.find_files import (find_files, Match)


# Recursively find all *.txt files in **/home/**
txt_files_pattern = Match(filetype='f', name='*.txt')
found_files = find_files(path='/home', match=txt_files_pattern)

for found_file in found_files:
    print found_file

có thể được cài đặt với

pip install findtools


1

Bạn có thể sử dụng pathlib có sẵn trong thư viện tiêu chuẩn Python 3.4 trở lên.

from pathlib import Path

files = [f for f in Path.cwd().iterdir() if f.match("145592*.jpg")]

1

Bạn có thể xác định mô hình và kiểm tra nó. Ở đây tôi đã lấy cả mẫu bắt đầu và kết thúc và tìm kiếm chúng trong tên tệp. PHIM chứa danh sách tất cả các tệp trong một thư mục.

import os
PATTERN_START = "145592"
PATTERN_END = ".jpg"
CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
for r,d,FILES in os.walk(CURRENT_DIR):
    for FILE in FILES:
        if PATTERN_START in FILE and PATTERN_END in FILE:
            print FILE

0

Làm thế nào về str.split ()? Không có gì để nhập khẩu.

import os

image_names = [f for f in os.listdir(path) if len(f.split('.jpg')) == 2]

2
Điều này rất giống với câu trả lời của @gypsy
Sushanth

Điều này có vẻ giống với câu trả lời của @ ramsey0 bằng cách sử dụng f.endswith('.jpg')(nhưng cũng sẽ chọn filename.jpg.ext)
anjsimmo

-1

Bạn có thể sử dụng sub process.check_ouput () làm

import subprocess

list_files = subprocess.check_output("ls 145992*.jpg", shell=True) 

Tất nhiên, chuỗi giữa các trích dẫn có thể là bất cứ điều gì bạn muốn thực hiện trong trình bao và lưu trữ đầu ra.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.