Làm thế nào để tôi liệt kê tất cả các tập tin của một thư mục?


3473

Làm cách nào tôi có thể liệt kê tất cả các tệp của một thư mục trong Python và thêm chúng vào một list?


Câu trả lời:


4215

os.listdir()sẽ giúp bạn có mọi thứ trong một thư mục - tệpthư mục .

Nếu bạn chỉ muốn các tệp, bạn có thể lọc phần này xuống bằng cách sử dụng os.path:

from os import listdir
from os.path import isfile, join
onlyfiles = [f for f in listdir(mypath) if isfile(join(mypath, f))]

hoặc bạn có thể sử dụng os.walk()mà sẽ mang lại hai danh sách cho mỗi thư mục đó thăm - chia tách thành các filedirs cho bạn. Nếu bạn chỉ muốn thư mục trên cùng, bạn chỉ có thể phá vỡ lần đầu tiên nó mang lại

from os import walk

f = []
for (dirpath, dirnames, filenames) in walk(mypath):
    f.extend(filenames)
    break

87
Đơn giản hơn một chút: (_, _, filenames) = walk(mypath).next() (nếu bạn tự tin rằng cuộc đi bộ sẽ trả lại ít nhất một giá trị, điều đó nên.)
misterbee

9
Sửa đổi nhẹ để lưu trữ các đường dẫn đầy đủ: for (dirpath, dirnames, filenames) trong os.walk (mypath): checksum_files.extend (os.path.join (dirpath, tên tệp) cho tên tệp trong tên tệp) break
okigan

150
f.extend(filenames)không thực sự tương đương với f = f + filenames. extendsẽ sửa đổi ftại chỗ, trong khi thêm sẽ tạo một danh sách mới trong một vị trí bộ nhớ mới. Điều này có nghĩa extendlà thường hiệu quả hơn +, nhưng đôi khi có thể dẫn đến nhầm lẫn nếu nhiều đối tượng giữ các tham chiếu đến danh sách. Cuối cùng, đáng chú ý f += filenameslà tương đương với f.extend(filenames), không f = f + filenames .
Benjamin Hodgson

30
@misterbee, giải pháp của bạn là tốt nhất, chỉ cần một cải tiến nhỏ:_, _, filenames = next(walk(mypath), (None, None, []))
bgusach

35
sử dụng python 3.x(_, _, filenames) = next(os.walk(mypath))
ET-CS

1683

Tôi thích sử dụng globmô-đun, vì nó phù hợp với mô hình và mở rộng.

import glob
print(glob.glob("/home/adam/*.txt"))

Nó sẽ trả về một danh sách với các tệp được yêu cầu:

['/home/adam/file1.txt', '/home/adam/file2.txt', .... ]

17
đó là một phím tắt cho listdir + fnmatch docs.python.org/library/fnmatch.html#fnmatch.fnmatch
Stefano

31
để làm rõ, điều này không trả về "đường dẫn đầy đủ"; nó chỉ đơn giản trả về sự mở rộng của toàn cầu, bất kể nó có thể là gì. Ví dụ, được đưa ra /home/user/foo/bar/hello.txt, sau đó, nếu chạy trong thư mục foo, glob("bar/*.txt")sẽ trở lại bar/hello.txt. Có những trường hợp khi bạn thực tế muốn đường dẫn đầy đủ (tức là tuyệt đối); đối với những trường hợp đó, hãy xem stackoverflow.com/questions/51520/ Cách
michael

1
Liên quan: tìm tệp đệ quy với global: stackoverflow.com/a/2186565/4561887
Gabriel Staples

6
không trả lời câu hỏi này glob.glob("*")sẽ.
Jean-François Fabre

xinh đẹp!!!! vì vậy .... x=glob.glob("../train/*.png")sẽ cho tôi một mảng các đường dẫn của tôi, miễn là tôi biết tên của thư mục. Thật tuyệt!
Jennifer Crosby

858

Nhận danh sách các tệp với Python 2 và 3


os.listdir()

Cách nhận tất cả các tệp (và thư mục) trong thư mục hiện tại (Python 3)

Sau đây, là các phương pháp đơn giản để chỉ truy xuất các tệp trong thư mục hiện tại, sử dụng oslistdir()hàm, trong Python 3. Khám phá thêm, sẽ trình bày cách trả lại các thư mục trong thư mục, nhưng bạn sẽ không có tệp trong thư mục con, cho bạn có thể sử dụng đi bộ - thảo luận sau).

 import os
 arr = os.listdir()
 print(arr)

 >>> ['$RECYCLE.BIN', 'work.txt', '3ebooks.txt', 'documents']

glob

Tôi thấy toàn cầu dễ dàng hơn để chọn tệp cùng loại hoặc có điểm chung. Nhìn vào ví dụ sau:

import glob

txtfiles = []
for file in glob.glob("*.txt"):
    txtfiles.append(file)

glob với sự hiểu biết danh sách

import glob

mylist = [f for f in glob.glob("*.txt")]

glob với một chức năng

Hàm trả về một danh sách các phần mở rộng đã cho (.txt, .docx ecc.) Trong đối số

import glob

def filebrowser(ext=""):
    "Returns files with an extension"
    return [f for f in glob.glob(f"*{ext}")]

x = filebrowser(".txt")
print(x)

>>> ['example.txt', 'fb.txt', 'intro.txt', 'help.txt']

glob mở rộng mã trước đó

Hàm bây giờ trả về một danh sách các tệp khớp với chuỗi bạn truyền làm đối số

import glob

def filesearch(word=""):
    """Returns a list with all files with the word/extension in it"""
    file = []
    for f in glob.glob("*"):
        if word[0] == ".":
            if f.endswith(word):
                file.append(f)
                return file
        elif word in f:
            file.append(f)
            return file
    return file

lookfor = "example", ".py"
for w in lookfor:
    print(f"{w:10} found => {filesearch(w)}")

đầu ra

example    found => []
.py        found => ['search.py']

Lấy tên đường dẫn đầy đủ với os.path.abspath

Như bạn nhận thấy, bạn không có đường dẫn đầy đủ của tệp trong mã ở trên. Nếu bạn cần phải có đường dẫn tuyệt đối, bạn có thể sử dụng một chức năng khác của os.pathmô-đun được gọi _getfullpathname, đặt tệp mà bạn nhận được os.listdir()làm đối số. Có nhiều cách khác để có đường dẫn đầy đủ, vì chúng tôi sẽ kiểm tra sau (tôi đã thay thế, như được đề xuất bởi mexmex, _getfullpathname với abspath).

 import os
 files_path = [os.path.abspath(x) for x in os.listdir()]
 print(files_path)

 >>> ['F:\\documenti\applications.txt', 'F:\\documenti\collections.txt']

Lấy tên đường dẫn đầy đủ của một loại tệp vào tất cả các thư mục con với walk

Tôi thấy điều này rất hữu ích để tìm nội dung trong nhiều thư mục và nó đã giúp tôi tìm một tệp mà tôi không nhớ tên:

import os

# Getting the current work directory (cwd)
thisdir = os.getcwd()

# r=root, d=directories, f = files
for r, d, f in os.walk(thisdir):
    for file in f:
        if file.endswith(".docx"):
            print(os.path.join(r, file))

os.listdir(): lấy tệp trong thư mục hiện tại (Python 2)

Trong Python 2, nếu bạn muốn danh sách các tệp trong thư mục hiện tại, bạn phải đưa ra đối số là '.' hoặc os.getcwd () trong phương thức os.listdir.

 import os
 arr = os.listdir('.')
 print(arr)

 >>> ['$RECYCLE.BIN', 'work.txt', '3ebooks.txt', 'documents']

Để đi lên trong cây thư mục

# Method 1
x = os.listdir('..')

# Method 2
x= os.listdir('/')

Nhận tệp: os.listdir()trong một thư mục cụ thể (Python 2 và 3)

 import os
 arr = os.listdir('F:\\python')
 print(arr)

 >>> ['$RECYCLE.BIN', 'work.txt', '3ebooks.txt', 'documents']

Nhận tệp của thư mục con cụ thể với os.listdir()

import os

x = os.listdir("./content")

os.walk('.') - thư mục hiện tại

 import os
 arr = next(os.walk('.'))[2]
 print(arr)

 >>> ['5bs_Turismo1.pdf', '5bs_Turismo1.pptx', 'esperienza.txt']

next(os.walk('.'))os.path.join('dir', 'file')

 import os
 arr = []
 for d,r,f in next(os.walk("F:\\_python")):
     for file in f:
         arr.append(os.path.join(r,file))

 for f in arr:
     print(files)

>>> F:\\_python\\dict_class.py
>>> F:\\_python\\programmi.txt

next(os.walk('F:\\') - có được đường dẫn đầy đủ - hiểu danh sách

 [os.path.join(r,file) for r,d,f in next(os.walk("F:\\_python")) for file in f]

 >>> ['F:\\_python\\dict_class.py', 'F:\\_python\\programmi.txt']

os.walk - nhận đường dẫn đầy đủ - tất cả các tệp trong thư mục con **

x = [os.path.join(r,file) for r,d,f in os.walk("F:\\_python") for file in f]
print(x)

>>> ['F:\\_python\\dict.py', 'F:\\_python\\progr.txt', 'F:\\_python\\readl.py']

os.listdir() - chỉ nhận các tệp txt

 arr_txt = [x for x in os.listdir() if x.endswith(".txt")]
 print(arr_txt)

 >>> ['work.txt', '3ebooks.txt']

Sử dụng globđể có được đường dẫn đầy đủ của các tập tin

Nếu tôi cần đường dẫn tuyệt đối của các tập tin:

from path import path
from glob import glob
x = [path(f).abspath() for f in glob("F:\\*.txt")]
for f in x:
    print(f)

>>> F:\acquistionline.txt
>>> F:\acquisti_2018.txt
>>> F:\bootstrap_jquery_ecc.txt

Sử dụng os.path.isfileđể tránh các thư mục trong danh sách

import os.path
listOfFiles = [f for f in os.listdir() if os.path.isfile(f)]
print(listOfFiles)

>>> ['a simple game.py', 'data.txt', 'decorator.py']

Sử dụng pathlibtừ Python 3.4

import pathlib

flist = []
for p in pathlib.Path('.').iterdir():
    if p.is_file():
        print(p)
        flist.append(p)

 >>> error.PNG
 >>> exemaker.bat
 >>> guiprova.mp3
 >>> setup.py
 >>> speak_gui2.py
 >>> thumb.PNG

Với list comprehension:

flist = [p for p in pathlib.Path('.').iterdir() if p.is_file()]

Cách khác, sử dụng pathlib.Path()thay vìpathlib.Path(".")

Sử dụng phương thức toàn cầu trong pathlib.Path ()

import pathlib

py = pathlib.Path().glob("*.py")
for file in py:
    print(file)

>>> stack_overflow_list.py
>>> stack_overflow_list_tkinter.py

Nhận tất cả và chỉ các tệp với os.walk

import os
x = [i[2] for i in os.walk('.')]
y=[]
for t in x:
    for f in t:
        y.append(f)
print(y)

>>> ['append_to_list.py', 'data.txt', 'data1.txt', 'data2.txt', 'data_180617', 'os_walk.py', 'READ2.py', 'read_data.py', 'somma_defaltdic.py', 'substitute_words.py', 'sum_data.py', 'data.txt', 'data1.txt', 'data_180617']

Chỉ nhận các tệp với tiếp theo và đi bộ trong một thư mục

 import os
 x = next(os.walk('F://python'))[2]
 print(x)

 >>> ['calculator.bat','calculator.py']

Chỉ nhận các thư mục tiếp theo và đi bộ trong một thư mục

 import os
 next(os.walk('F://python'))[1] # for the current dir use ('.')

 >>> ['python3','others']

Nhận tất cả các tên phụ với walk

for r,d,f in os.walk("F:\\_python"):
    for dirs in d:
        print(dirs)

>>> .vscode
>>> pyexcel
>>> pyschool.py
>>> subtitles
>>> _metaprogramming
>>> .ipynb_checkpoints

os.scandir() từ Python 3.5 trở lên

import os
x = [f.name for f in os.scandir() if f.is_file()]
print(x)

>>> ['calculator.bat','calculator.py']

# Another example with scandir (a little variation from docs.python.org)
# This one is more efficient than os.listdir.
# In this case, it shows the files only in the current directory
# where the script is executed.

import os
with os.scandir() as i:
    for entry in i:
        if entry.is_file():
            print(entry.name)

>>> ebookmaker.py
>>> error.PNG
>>> exemaker.bat
>>> guiprova.mp3
>>> setup.py
>>> speakgui4.py
>>> speak_gui2.py
>>> speak_gui3.py
>>> thumb.PNG

Ví dụ:

Ví dụ. 1: Có bao nhiêu tệp trong thư mục con?

Trong ví dụ này, chúng tôi tìm kiếm số lượng tệp được bao gồm trong tất cả các thư mục và thư mục con của nó.

import os

def count(dir, counter=0):
    "returns number of files in dir and subdirs"
    for pack in os.walk(dir):
        for f in pack[2]:
            counter += 1
    return dir + " : " + str(counter) + "files"

print(count("F:\\python"))

>>> 'F:\\\python' : 12057 files'

Ex.2: Làm thế nào để sao chép tất cả các tệp từ một thư mục sang một thư mục khác?

Một tập lệnh để đặt hàng trong máy tính của bạn tìm tất cả các tệp thuộc loại (mặc định: pptx) và sao chép chúng trong một thư mục mới.

import os
import shutil
from path import path

destination = "F:\\file_copied"
# os.makedirs(destination)

def copyfile(dir, filetype='pptx', counter=0):
    "Searches for pptx (or other - pptx is the default) files and copies them"
    for pack in os.walk(dir):
        for f in pack[2]:
            if f.endswith(filetype):
                fullpath = pack[0] + "\\" + f
                print(fullpath)
                shutil.copy(fullpath, destination)
                counter += 1
    if counter > 0:
        print('-' * 30)
        print("\t==> Found in: `" + dir + "` : " + str(counter) + " files\n")

for dir in os.listdir():
    "searches for folders that starts with `_`"
    if dir[0] == '_':
        # copyfile(dir, filetype='pdf')
        copyfile(dir, filetype='txt')


>>> _compiti18\Compito Contabilità 1\conti.txt
>>> _compiti18\Compito Contabilità 1\modula4.txt
>>> _compiti18\Compito Contabilità 1\moduloa4.txt
>>> ------------------------
>>> ==> Found in: `_compiti18` : 3 files

Ví dụ. 3: Cách nhận tất cả các tệp trong tệp txt

Trong trường hợp bạn muốn tạo một tệp txt với tất cả các tên tệp:

import os
mylist = ""
with open("filelist.txt", "w", encoding="utf-8") as file:
    for eachfile in os.listdir():
        mylist += eachfile + "\n"
    file.write(mylist)

Ví dụ: txt với tất cả các tệp của ổ cứng

"""
We are going to save a txt file with all the files in your directory.
We will use the function walk()
"""

import os

# see all the methods of os
# print(*dir(os), sep=", ")
listafile = []
percorso = []
with open("lista_file.txt", "w", encoding='utf-8') as testo:
    for root, dirs, files in os.walk("D:\\"):
        for file in files:
            listafile.append(file)
            percorso.append(root + "\\" + file)
            testo.write(file + "\n")
listafile.sort()
print("N. of files", len(listafile))
with open("lista_file_ordinata.txt", "w", encoding="utf-8") as testo_ordinato:
    for file in listafile:
        testo_ordinato.write(file + "\n")

with open("percorso.txt", "w", encoding="utf-8") as file_percorso:
    for file in percorso:
        file_percorso.write(file + "\n")

os.system("lista_file.txt")
os.system("lista_file_ordinata.txt")
os.system("percorso.txt")

Tất cả tệp của C: \ trong một tệp văn bản

Đây là một phiên bản ngắn hơn của mã trước đó. Thay đổi thư mục nơi bắt đầu tìm tệp nếu bạn cần bắt đầu từ vị trí khác. Mã này tạo ra 50 mb trên tệp văn bản trên máy tính của tôi với khoảng 500.000 dòng với các tệp có đường dẫn đầy đủ.

import os

with open("file.txt", "w", encoding="utf-8") as filewrite:
    for r, d, f in os.walk("C:\\"):
        for file in f:
            filewrite.write(f"{r + file}\n")

Cách viết một tệp với tất cả các đường dẫn trong một thư mục thuộc loại

Với chức năng này, bạn có thể tạo một tệp txt sẽ có tên của một loại tệp mà bạn tìm kiếm (ví dụ: pngfile.txt) với tất cả đường dẫn đầy đủ của tất cả các tệp thuộc loại đó. Nó có thể hữu ích đôi khi, tôi nghĩ.

import os

def searchfiles(extension='.ttf', folder='H:\\'):
    "Create a txt file with all the file of a type"
    with open(extension[1:] + "file.txt", "w", encoding="utf-8") as filewrite:
        for r, d, f in os.walk(folder):
            for file in f:
                if file.endswith(extension):
                    filewrite.write(f"{r + file}\n")

# looking for png file (fonts) in the hard disk H:\
searchfiles('.png', 'H:\\')

>>> H:\4bs_18\Dolphins5.png
>>> H:\4bs_18\Dolphins6.png
>>> H:\4bs_18\Dolphins7.png
>>> H:\5_18\marketing html\assets\imageslogo2.png
>>> H:\7z001.png
>>> H:\7z002.png

(Mới) Tìm tất cả các tệp và mở chúng bằng GUI tkinter

Tôi chỉ muốn thêm vào năm 2019 một ứng dụng nhỏ này để tìm kiếm tất cả các tệp trong một thư mục và có thể mở chúng bằng cách nhân đôi tên của tệp trong danh sách. nhập mô tả hình ảnh ở đây

import tkinter as tk
import os

def searchfiles(extension='.txt', folder='H:\\'):
    "insert all files in the listbox"
    for r, d, f in os.walk(folder):
        for file in f:
            if file.endswith(extension):
                lb.insert(0, r + "\\" + file)

def open_file():
    os.startfile(lb.get(lb.curselection()[0]))

root = tk.Tk()
root.geometry("400x400")
bt = tk.Button(root, text="Search", command=lambda:searchfiles('.png', 'H:\\'))
bt.pack()
lb = tk.Listbox(root)
lb.pack(fill="both", expand=1)
lb.bind("<Double-Button>", lambda x: open_file())
root.mainloop()

14
Đây là một mớ hỗn độn của quá nhiều câu trả lời cho các câu hỏi không được hỏi ở đây. Nó cũng có thể đáng để giải thích những gì hãy cẩn thận hoặc phương pháp tiếp cận được đề nghị. Tôi không tốt hơn khi biết một cách so với 20 cách để làm điều tương tự trừ khi tôi cũng biết cách nào phù hợp hơn để sử dụng khi nào.
cs95

Ok, càng sớm càng tốt, tôi sẽ xem câu trả lời của mình và cố gắng làm cho nó rõ ràng hơn và với nhiều thông tin hữu ích hơn về sự khác biệt giữa các phương pháp, v.v.
Giovanni G. PY

Bạn không nên xác định phần mở rộng của tệp bằng cách kiểm tra xem tên tệp có chứa chuỗi con không. Điều đó có thể gây ra nhiều rắc rối. Tôi khuyên bạn luôn luôn kiểm tra xem tên tệp kết thúc bằng chuỗi con cụ thể.
ni1ight

Ok, @ n1light Tôi đã thay đổi mã ...
Giovanni G. PY

811
import os
os.listdir("somedirectory")

sẽ trả về một danh sách tất cả các tệp và thư mục trong "somedirectory".


11
Điều này trả về đường dẫn tương đối của các tệp, so với đường dẫn đầy đủ được trả về bởiglob.glob
xji

22
@JIXiang: os.listdir()luôn trả về tên tệp đơn thuần (không phải đường dẫn tương đối). Những gì glob.glob()trả về được điều khiển bởi định dạng đường dẫn của mẫu đầu vào.
mkuity0

os.listdir () -> Nó luôn liệt kê thư mục và tệp bên trong vị trí được cung cấp. Có cách nào để liệt kê chỉ thư mục không tập tin?
RonyA

160

Một giải pháp một dòng để chỉ nhận danh sách các tệp (không có thư mục con):

filenames = next(os.walk(path))[2]

hoặc tên đường dẫn tuyệt đối:

paths = [os.path.join(path, fn) for fn in next(os.walk(path))[2]]

7
Chỉ một lớp lót nếu bạn đã có import os. Có vẻ ít súc tích hơn glob()với tôi.
ArtOfWarfare

4
vấn đề với global là một thư mục có tên 'Something.s Something' sẽ được trả về bởi global ('/ home / adam /*.*')
Remi

6
Trên OS X, có một thứ gọi là gói. Đó là một thư mục thường được coi là một tệp (như .tar). Bạn có muốn những người được coi là một tập tin hoặc một thư mục? Sử dụng glob()sẽ coi nó như một tập tin. Phương pháp của bạn sẽ coi nó như một thư mục.
ArtOfWarfare

132

Nhận đường dẫn tệp đầy đủ từ một thư mục và tất cả các thư mục con của nó

import os

def get_filepaths(directory):
    """
    This function will generate the file names in a directory 
    tree by walking the tree either top-down or bottom-up. For each 
    directory in the tree rooted at directory top (including top itself), 
    it yields a 3-tuple (dirpath, dirnames, filenames).
    """
    file_paths = []  # List which will store all of the full filepaths.

    # Walk the tree.
    for root, directories, files in os.walk(directory):
        for filename in files:
            # Join the two strings in order to form the full filepath.
            filepath = os.path.join(root, filename)
            file_paths.append(filepath)  # Add it to the list.

    return file_paths  # Self-explanatory.

# Run the above function and store its results in a variable.   
full_file_paths = get_filepaths("/Users/johnny/Desktop/TEST")

  • Đường dẫn tôi cung cấp trong hàm trên chứa 3 tệp. Hai tệp trong thư mục gốc và một tệp khác trong thư mục con có tên là "SUBFOLDER". Bây giờ bạn có thể làm những việc như:
  • print full_file_paths sẽ in danh sách:

    • ['/Users/johnny/Desktop/TEST/file1.txt', '/Users/johnny/Desktop/TEST/file2.txt', '/Users/johnny/Desktop/TEST/SUBFOLDER/file3.dat']

Nếu bạn muốn, bạn có thể mở và đọc nội dung hoặc chỉ tập trung vào các tệp có phần mở rộng ".dat" như trong mã dưới đây:

for f in full_file_paths:
  if f.endswith(".dat"):
    print f

/Users/johnny/Desktop/TEST/SUBFOLDER/file3.dat


Đây là câu trả lời duy nhất.
thelearner

78

Kể từ phiên bản 3.4, có các trình vòng lặp dựng sẵn cho việc này hiệu quả hơn nhiều so với os.listdir():

pathlib: Mới trong phiên bản 3.4.

>>> import pathlib
>>> [p for p in pathlib.Path('.').iterdir() if p.is_file()]

Theo PEP 428 , mục tiêu của pathlibthư viện là cung cấp một hệ thống phân cấp đơn giản các lớp để xử lý các đường dẫn hệ thống tệp và các hoạt động phổ biến mà người dùng thực hiện đối với chúng.

os.scandir(): Mới trong phiên bản 3.5.

>>> import os
>>> [entry for entry in os.scandir('.') if entry.is_file()]

Lưu ý rằng os.walk()sử dụng os.scandir()thay vì os.listdir()từ phiên bản 3.5 và tốc độ của nó đã tăng gấp 2-20 lần theo PEP 471 .

Tôi cũng khuyên bạn nên đọc bình luận của ShadowRanger bên dưới.


1
Cảm ơn! Tôi nghĩ đó là giải pháp duy nhất không trở lại trực tiếp a list. Có thể sử dụng p.namethay pthế thay thế đầu tiên nếu thích.
jeromej

1
Chào mừng bạn Tôi muốn tạo các pathlib.Path()thể hiện vì chúng có nhiều phương thức hữu ích mà tôi không muốn lãng phí. Bạn cũng có thể gọi str(p)chúng cho tên đường dẫn.
SzieberthAdam

6
Lưu ý: os.scandirGiải pháp sẽ hiệu quả hơn so os.listdirvới os.path.is_filekiểm tra hoặc tương tự, ngay cả khi bạn cần list(vì vậy bạn không được hưởng lợi từ việc lặp lại lười biếng), bởi vì os.scandirsử dụng API do OS cung cấp cung cấp cho bạn is_filethông tin miễn phí khi lặp lại , không có mỗi tập tin chuyến đi vòng vào đĩa để statchúng ở tất cả (trên Windows, các DirEntrys giúp bạn hoàn chỉnh statthông tin miễn phí, trên hệ thống * NIX nó cần phải statđể biết vượt qua is_file, is_dir, vv, nhưng DirEntrybộ nhớ đệm trên đầu statcho thuận tiện).
ShadowRanger

1
Bạn cũng có thể sử dụng entry.nameđể chỉ lấy tên tệp hoặc entry.pathđể có đường dẫn đầy đủ. Không còn os.path.join () ở khắp mọi nơi.
dùng136036

56

Ghi chú sơ bộ

  • Mặc dù có sự khác biệt rõ ràng giữa tập tin thư mục điều khoản trong văn bản câu hỏi, một số người có thể lập luận rằng các thư mục thực sự là các tệp đặc biệt
  • Tuyên bố: " tất cả các tệp của một thư mục " có thể được hiểu theo hai cách:
    1. Tất cả trực tiếp (hoặc cấp 1) hậu duệ duy nhất
    2. Tất cả các hậu duệ trong toàn bộ cây thư mục (bao gồm cả những người trong thư mục con)
  • Khi câu hỏi được hỏi, tôi tưởng tượng rằng Python 2 , là phiên bản LTS , tuy nhiên các mẫu mã sẽ được chạy bởi Python 3 ( .5 ) (Tôi sẽ giữ chúng theo tiêu chuẩn Python 2 nhất có thể; Python mà tôi sẽ đăng, là từ phiên bản 3.5.4 - trừ khi có quy định khác). Điều đó có hậu quả liên quan đến một từ khóa khác trong câu hỏi: " thêm chúng vào danh sách ":

    • Trong các phiên bản Python 2.2 trước , các chuỗi (iterables) hầu hết được biểu thị bằng các danh sách (bộ, bộ, ...)
    • Trong Python 2.2 , khái niệm về trình tạo ( [Python.Wiki]: Generators ) - lịch sự của [Python 3]: Tuyên bố năng suất ) - đã được giới thiệu. Thời gian trôi qua, các đối tác của trình tạo bắt đầu xuất hiện cho các hàm trả về / làm việc với danh sách
    • Trong Python 3 , trình tạo là hành vi mặc định
    • Không chắc chắn nếu trả về một danh sách vẫn là bắt buộc (hoặc một trình tạo cũng sẽ làm như vậy), nhưng việc chuyển một trình tạo đến hàm tạo danh sách , sẽ tạo ra một danh sách từ đó (và cũng tiêu thụ nó). Ví dụ dưới đây minh họa sự khác biệt trên [Python 3]: map ( function, iterable, ... )
    >>> import sys
    >>> sys.version
    '2.7.10 (default, Mar  8 2016, 15:02:46) [MSC v.1600 64 bit (AMD64)]'
    >>> m = map(lambda x: x, [1, 2, 3])  # Just a dummy lambda function
    >>> m, type(m)
    ([1, 2, 3], <type 'list'>)
    >>> len(m)
    3


    >>> import sys
    >>> sys.version
    '3.5.4 (v3.5.4:3f56838, Aug  8 2017, 02:17:05) [MSC v.1900 64 bit (AMD64)]'
    >>> m = map(lambda x: x, [1, 2, 3])
    >>> m, type(m)
    (<map object at 0x000001B4257342B0>, <class 'map'>)
    >>> len(m)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: object of type 'map' has no len()
    >>> lm0 = list(m)  # Build a list from the generator
    >>> lm0, type(lm0)
    ([1, 2, 3], <class 'list'>)
    >>>
    >>> lm1 = list(m)  # Build a list from the same generator
    >>> lm1, type(lm1)  # Empty list now - generator already consumed
    ([], <class 'list'>)
  • Các ví dụ sẽ dựa trên một thư mục có tên root_dir với cấu trúc sau (ví dụ này là dành cho Win , nhưng tôi cũng đang sử dụng cùng một cây trên Lnx ):

    E:\Work\Dev\StackOverflow\q003207219>tree /f "root_dir"
    Folder PATH listing for volume Work
    Volume serial number is 00000029 3655:6FED
    E:\WORK\DEV\STACKOVERFLOW\Q003207219\ROOT_DIR
    ¦   file0
    ¦   file1
    ¦
    +---dir0
    ¦   +---dir00
    ¦   ¦   ¦   file000
    ¦   ¦   ¦
    ¦   ¦   +---dir000
    ¦   ¦           file0000
    ¦   ¦
    ¦   +---dir01
    ¦   ¦       file010
    ¦   ¦       file011
    ¦   ¦
    ¦   +---dir02
    ¦       +---dir020
    ¦           +---dir0200
    +---dir1
    ¦       file10
    ¦       file11
    ¦       file12
    ¦
    +---dir2
    ¦   ¦   file20
    ¦   ¦
    ¦   +---dir20
    ¦           file200
    ¦
    +---dir3


Các giải pháp

Phương pháp lập trình:

  1. [Python 3]: os. listdir ( path = '.' )

    Trả về một danh sách chứa tên của các mục trong thư mục được cung cấp bởi đường dẫn. Danh sách theo thứ tự tùy ý và không bao gồm các mục đặc biệt '.''..'...


    >>> import os
    >>> root_dir = "root_dir"  # Path relative to current dir (os.getcwd())
    >>>
    >>> os.listdir(root_dir)  # List all the items in root_dir
    ['dir0', 'dir1', 'dir2', 'dir3', 'file0', 'file1']
    >>>
    >>> [item for item in os.listdir(root_dir) if os.path.isfile(os.path.join(root_dir, item))]  # Filter items and only keep files (strip out directories)
    ['file0', 'file1']

    Một ví dụ phức tạp hơn ( code_os_listdir.py ):

    import os
    from pprint import pformat
    
    
    def _get_dir_content(path, include_folders, recursive):
        entries = os.listdir(path)
        for entry in entries:
            entry_with_path = os.path.join(path, entry)
            if os.path.isdir(entry_with_path):
                if include_folders:
                    yield entry_with_path
                if recursive:
                    for sub_entry in _get_dir_content(entry_with_path, include_folders, recursive):
                        yield sub_entry
            else:
                yield entry_with_path
    
    
    def get_dir_content(path, include_folders=True, recursive=True, prepend_folder_name=True):
        path_len = len(path) + len(os.path.sep)
        for item in _get_dir_content(path, include_folders, recursive):
            yield item if prepend_folder_name else item[path_len:]
    
    
    def _get_dir_content_old(path, include_folders, recursive):
        entries = os.listdir(path)
        ret = list()
        for entry in entries:
            entry_with_path = os.path.join(path, entry)
            if os.path.isdir(entry_with_path):
                if include_folders:
                    ret.append(entry_with_path)
                if recursive:
                    ret.extend(_get_dir_content_old(entry_with_path, include_folders, recursive))
            else:
                ret.append(entry_with_path)
        return ret
    
    
    def get_dir_content_old(path, include_folders=True, recursive=True, prepend_folder_name=True):
        path_len = len(path) + len(os.path.sep)
        return [item if prepend_folder_name else item[path_len:] for item in _get_dir_content_old(path, include_folders, recursive)]
    
    
    def main():
        root_dir = "root_dir"
        ret0 = get_dir_content(root_dir, include_folders=True, recursive=True, prepend_folder_name=True)
        lret0 = list(ret0)
        print(ret0, len(lret0), pformat(lret0))
        ret1 = get_dir_content_old(root_dir, include_folders=False, recursive=True, prepend_folder_name=False)
        print(len(ret1), pformat(ret1))
    
    
    if __name__ == "__main__":
        main()

    Ghi chú :

    • Có hai cách thực hiện:
      • Một cái sử dụng máy phát điện (tất nhiên ở đây có vẻ như vô dụng, vì tôi ngay lập tức chuyển đổi kết quả thành một danh sách)
      • Kiểu cổ điển (tên hàm kết thúc bằng _old )
    • Đệ quy được sử dụng (để vào thư mục con)
    • Đối với mỗi thực hiện có hai chức năng:
      • Một bắt đầu bằng dấu gạch dưới ( _ ): "private" (không nên được gọi trực tiếp) - đó là tất cả công việc
      • Công khai (bao bọc so với trước): nó chỉ loại bỏ đường dẫn ban đầu (nếu cần) từ các mục được trả về. Đó là một triển khai xấu xí, nhưng đó là ý tưởng duy nhất mà tôi có thể đi kèm vào thời điểm này
    • Về hiệu suất, các trình tạo thường nhanh hơn một chút (xem xét cả việc tạolặp thời gian ), nhưng tôi đã không kiểm tra chúng trong các hàm đệ quy và tôi cũng đang lặp lại bên trong hàm trên các trình tạo bên trong - không biết hiệu suất như thế nào thân thiện là thế
    • Chơi với các đối số để có kết quả khác nhau


    Đầu ra :

    (py35x64_test) E:\Work\Dev\StackOverflow\q003207219>"e:\Work\Dev\VEnvs\py35x64_test\Scripts\python.exe" "code_os_listdir.py"
    <generator object get_dir_content at 0x000001BDDBB3DF10> 22 ['root_dir\\dir0',
     'root_dir\\dir0\\dir00',
     'root_dir\\dir0\\dir00\\dir000',
     'root_dir\\dir0\\dir00\\dir000\\file0000',
     'root_dir\\dir0\\dir00\\file000',
     'root_dir\\dir0\\dir01',
     'root_dir\\dir0\\dir01\\file010',
     'root_dir\\dir0\\dir01\\file011',
     'root_dir\\dir0\\dir02',
     'root_dir\\dir0\\dir02\\dir020',
     'root_dir\\dir0\\dir02\\dir020\\dir0200',
     'root_dir\\dir1',
     'root_dir\\dir1\\file10',
     'root_dir\\dir1\\file11',
     'root_dir\\dir1\\file12',
     'root_dir\\dir2',
     'root_dir\\dir2\\dir20',
     'root_dir\\dir2\\dir20\\file200',
     'root_dir\\dir2\\file20',
     'root_dir\\dir3',
     'root_dir\\file0',
     'root_dir\\file1']
    11 ['dir0\\dir00\\dir000\\file0000',
     'dir0\\dir00\\file000',
     'dir0\\dir01\\file010',
     'dir0\\dir01\\file011',
     'dir1\\file10',
     'dir1\\file11',
     'dir1\\file12',
     'dir2\\dir20\\file200',
     'dir2\\file20',
     'file0',
     'file1']


  1. [Python 3]: os. scandir ( path = '.' ) ( Python 3.5 +, backport: [PyPI]: scandir )

    Trả về một iterator của các đối tượng os.DirEntry tương ứng với các mục trong thư mục được cung cấp bởi đường dẫn . Các mục được mang lại theo thứ tự tùy ý, và các mục đặc biệt '.''..'không được bao gồm.

    Sử dụng scandir () thay cho listdir () có thể làm tăng đáng kể hiệu năng của mã cũng cần thông tin thuộc tính loại tệp hoặc thuộc tính tệp, vì các đối tượng os.DirEntry lộ thông tin này nếu hệ điều hành cung cấp nó khi quét thư mục. Tất cả các phương thức os.DirEntry có thể thực hiện một cuộc gọi hệ thống, nhưng is_dir ()is_file () thường chỉ yêu cầu một cuộc gọi hệ thống cho các liên kết tượng trưng; os.DirEntry.stat () luôn yêu cầu một cuộc gọi hệ thống trên Unix nhưng chỉ yêu cầu một liên kết tượng trưng trên Windows.


    >>> import os
    >>> root_dir = os.path.join(".", "root_dir")  # Explicitly prepending current directory
    >>> root_dir
    '.\\root_dir'
    >>>
    >>> scandir_iterator = os.scandir(root_dir)
    >>> scandir_iterator
    <nt.ScandirIterator object at 0x00000268CF4BC140>
    >>> [item.path for item in scandir_iterator]
    ['.\\root_dir\\dir0', '.\\root_dir\\dir1', '.\\root_dir\\dir2', '.\\root_dir\\dir3', '.\\root_dir\\file0', '.\\root_dir\\file1']
    >>>
    >>> [item.path for item in scandir_iterator]  # Will yield an empty list as it was consumed by previous iteration (automatically performed by the list comprehension)
    []
    >>>
    >>> scandir_iterator = os.scandir(root_dir)  # Reinitialize the generator
    >>> for item in scandir_iterator :
    ...     if os.path.isfile(item.path):
    ...             print(item.name)
    ...
    file0
    file1

    Ghi chú :

    • Nó tương tự như os.listdir
    • Nhưng nó cũng linh hoạt hơn (và cung cấp nhiều chức năng hơn), nhiều ic Python hơn (và trong một số trường hợp, nhanh hơn)


  1. [Python 3]: os. đi bộ ( top, topdown = True, onerror = Không, followlinks = Sai )

    Tạo tên tệp trong cây thư mục bằng cách đi bộ cây từ trên xuống hoặc từ dưới lên. Đối với mỗi thư mục trong cây bén rễ tại thư mục trên (bao gồm cả đầu chính nó), nó mang lại một 3-tuple ( dirpath, dirnames, filenames).


    >>> import os
    >>> root_dir = os.path.join(os.getcwd(), "root_dir")  # Specify the full path
    >>> root_dir
    'E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir'
    >>>
    >>> walk_generator = os.walk(root_dir)
    >>> root_dir_entry = next(walk_generator)  # First entry corresponds to the root dir (passed as an argument)
    >>> root_dir_entry
    ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir', ['dir0', 'dir1', 'dir2', 'dir3'], ['file0', 'file1'])
    >>>
    >>> root_dir_entry[1] + root_dir_entry[2]  # Display dirs and files (direct descendants) in a single list
    ['dir0', 'dir1', 'dir2', 'dir3', 'file0', 'file1']
    >>>
    >>> [os.path.join(root_dir_entry[0], item) for item in root_dir_entry[1] + root_dir_entry[2]]  # Display all the entries in the previous list by their full path
    ['E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir0', 'E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir1', 'E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir2', 'E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir3', 'E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\file0', 'E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\file1']
    >>>
    >>> for entry in walk_generator:  # Display the rest of the elements (corresponding to every subdir)
    ...     print(entry)
    ...
    ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir0', ['dir00', 'dir01', 'dir02'], [])
    ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir0\\dir00', ['dir000'], ['file000'])
    ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir0\\dir00\\dir000', [], ['file0000'])
    ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir0\\dir01', [], ['file010', 'file011'])
    ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir0\\dir02', ['dir020'], [])
    ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir0\\dir02\\dir020', ['dir0200'], [])
    ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir0\\dir02\\dir020\\dir0200', [], [])
    ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir1', [], ['file10', 'file11', 'file12'])
    ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir2', ['dir20'], ['file20'])
    ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir2\\dir20', [], ['file200'])
    ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir3', [], [])

    Ghi chú :

    • Trong các cảnh, nó sử dụng os.scandir( os.listdirtrên các phiên bản cũ hơn)
    • Nó thực hiện việc nâng vật nặng bằng cách định kỳ trong các thư mục con


  1. [Python 3]: toàn cầu. global ( tên đường dẫn, *, đệ quy = Sai ) ( [Python 3]: global . iglob ( tên đường dẫn, *, đệ quy = Sai ) )

    Trả về một danh sách các tên đường dẫn có thể trống khớp với tên đường dẫn , phải là một chuỗi chứa một đặc tả đường dẫn. tên đường dẫn có thể là tuyệt đối (như /usr/src/Python-1.5/Makefile) hoặc tương đối (như ../../Tools/*/*.gif) và có thể chứa các ký tự đại diện kiểu vỏ. Symlink bị hỏng được bao gồm trong các kết quả (như trong vỏ).
    ...
    Đã thay đổi trong phiên bản 3.5 : Hỗ trợ các thuật toán đệ quy bằng cách sử dụng **.


    >>> import glob, os
    >>> wildcard_pattern = "*"
    >>> root_dir = os.path.join("root_dir", wildcard_pattern)  # Match every file/dir name
    >>> root_dir
    'root_dir\\*'
    >>>
    >>> glob_list = glob.glob(root_dir)
    >>> glob_list
    ['root_dir\\dir0', 'root_dir\\dir1', 'root_dir\\dir2', 'root_dir\\dir3', 'root_dir\\file0', 'root_dir\\file1']
    >>>
    >>> [item.replace("root_dir" + os.path.sep, "") for item in glob_list]  # Strip the dir name and the path separator from begining
    ['dir0', 'dir1', 'dir2', 'dir3', 'file0', 'file1']
    >>>
    >>> for entry in glob.iglob(root_dir + "*", recursive=True):
    ...     print(entry)
    ...
    root_dir\
    root_dir\dir0
    root_dir\dir0\dir00
    root_dir\dir0\dir00\dir000
    root_dir\dir0\dir00\dir000\file0000
    root_dir\dir0\dir00\file000
    root_dir\dir0\dir01
    root_dir\dir0\dir01\file010
    root_dir\dir0\dir01\file011
    root_dir\dir0\dir02
    root_dir\dir0\dir02\dir020
    root_dir\dir0\dir02\dir020\dir0200
    root_dir\dir1
    root_dir\dir1\file10
    root_dir\dir1\file11
    root_dir\dir1\file12
    root_dir\dir2
    root_dir\dir2\dir20
    root_dir\dir2\dir20\file200
    root_dir\dir2\file20
    root_dir\dir3
    root_dir\file0
    root_dir\file1

    Ghi chú :

    • Công dụng os.listdir
    • Đối với cây lớn (đặc biệt là nếu đệ quy được bật), iglob được ưu tiên
    • Cho phép lọc nâng cao dựa trên tên (do ký tự đại diện)


  1. [Python 3]: lớp dẫn đường. Đường dẫn ( * đường dẫn ) ( Python 3,4 +, backport: [PyPI]: pathlib2 )

    >>> import pathlib
    >>> root_dir = "root_dir"
    >>> root_dir_instance = pathlib.Path(root_dir)
    >>> root_dir_instance
    WindowsPath('root_dir')
    >>> root_dir_instance.name
    'root_dir'
    >>> root_dir_instance.is_dir()
    True
    >>>
    >>> [item.name for item in root_dir_instance.glob("*")]  # Wildcard searching for all direct descendants
    ['dir0', 'dir1', 'dir2', 'dir3', 'file0', 'file1']
    >>>
    >>> [os.path.join(item.parent.name, item.name) for item in root_dir_instance.glob("*") if not item.is_dir()]  # Display paths (including parent) for files only
    ['root_dir\\file0', 'root_dir\\file1']

    Ghi chú :

    • Đây là một cách để đạt được mục tiêu của chúng tôi
    • Đó là kiểu xử lý OOP
    • Cung cấp rất nhiều chức năng


  1. [Python 2]: dircache.listdir (đường dẫn) (chỉ Python 2 )


    def listdir(path):
        """List directory contents, using cache."""
        try:
            cached_mtime, list = cache[path]
            del cache[path]
        except KeyError:
            cached_mtime, list = -1, []
        mtime = os.stat(path).st_mtime
        if mtime != cached_mtime:
            list = os.listdir(path)
            list.sort()
        cache[path] = mtime, list
        return list


  1. [man7]: OPENDIR (3) / [man7]: READDIR (3) / [man7]: ĐÃ ĐÓNG CỬA (3) qua [Python 3]: ctypes - Thư viện hàm nước ngoài cho Python ( cụ thể là POSIX )

    ctypes là một thư viện hàm nước ngoài cho Python. Nó cung cấp các kiểu dữ liệu tương thích C và cho phép gọi các hàm trong DLL hoặc thư viện dùng chung. Nó có thể được sử dụng để bọc các thư viện này trong Python thuần túy.

    code_ctypes.py :

    #!/usr/bin/env python3
    
    import sys
    from ctypes import Structure, \
        c_ulonglong, c_longlong, c_ushort, c_ubyte, c_char, c_int, \
        CDLL, POINTER, \
        create_string_buffer, get_errno, set_errno, cast
    
    
    DT_DIR = 4
    DT_REG = 8
    
    char256 = c_char * 256
    
    
    class LinuxDirent64(Structure):
        _fields_ = [
            ("d_ino", c_ulonglong),
            ("d_off", c_longlong),
            ("d_reclen", c_ushort),
            ("d_type", c_ubyte),
            ("d_name", char256),
        ]
    
    LinuxDirent64Ptr = POINTER(LinuxDirent64)
    
    libc_dll = this_process = CDLL(None, use_errno=True)
    # ALWAYS set argtypes and restype for functions, otherwise it's UB!!!
    opendir = libc_dll.opendir
    readdir = libc_dll.readdir
    closedir = libc_dll.closedir
    
    
    def get_dir_content(path):
        ret = [path, list(), list()]
        dir_stream = opendir(create_string_buffer(path.encode()))
        if (dir_stream == 0):
            print("opendir returned NULL (errno: {:d})".format(get_errno()))
            return ret
        set_errno(0)
        dirent_addr = readdir(dir_stream)
        while dirent_addr:
            dirent_ptr = cast(dirent_addr, LinuxDirent64Ptr)
            dirent = dirent_ptr.contents
            name = dirent.d_name.decode()
            if dirent.d_type & DT_DIR:
                if name not in (".", ".."):
                    ret[1].append(name)
            elif dirent.d_type & DT_REG:
                ret[2].append(name)
            dirent_addr = readdir(dir_stream)
        if get_errno():
            print("readdir returned NULL (errno: {:d})".format(get_errno()))
        closedir(dir_stream)
        return ret
    
    
    def main():
        print("{:s} on {:s}\n".format(sys.version, sys.platform))
        root_dir = "root_dir"
        entries = get_dir_content(root_dir)
        print(entries)
    
    
    if __name__ == "__main__":
        main()

    Ghi chú :

    • Nó tải ba hàm từ libc (được tải trong quy trình hiện tại) và gọi chúng (để biết thêm chi tiết kiểm tra [SO]: Làm cách nào để kiểm tra xem một tệp có tồn tại mà không có ngoại lệ không? (Câu trả lời của @ CristiFati) - ghi chú cuối từ mục số 4. ). Điều đó sẽ đặt phương pháp này rất gần với Python / C cạnh
    • LinuxDirent64 là đại diện ctypes của struct dirent64 từ [man7]: dirent.h (0P) (các hằng số DT_ ) từ máy của tôi: Ubtu 16 x64 ( 4.10.0-40-genericlibc6-dev: amd64 ). Trên các hương vị / phiên bản khác, định nghĩa cấu trúc có thể khác nhau và nếu vậy, bí danh ctypes sẽ được cập nhật, nếu không, nó sẽ mang lại Hành vi không xác định
    • Nó trả về dữ liệu ở os.walkđịnh dạng của. Tôi không bận tâm làm cho nó đệ quy, nhưng bắt đầu từ mã hiện có, đó sẽ là một nhiệm vụ khá nhỏ
    • Mọi thứ đều có thể thực hiện được trên Win , dữ liệu (thư viện, hàm, cấu trúc, hằng số, ...) khác nhau


    Đầu ra :

    [cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q003207219]> ./code_ctypes.py
    3.5.2 (default, Nov 12 2018, 13:43:14)
    [GCC 5.4.0 20160609] on linux
    
    ['root_dir', ['dir2', 'dir1', 'dir3', 'dir0'], ['file1', 'file0']]


  1. [ActiveState.Docs]: win32file.FindFilesW ( Thắng cụ thể)

    Lấy danh sách tên tệp phù hợp, sử dụng API Unicode của Windows. Giao diện cho API FindFirstFileW / FindNextFileW / Tìm các hàm đóng.


    >>> import os, win32file, win32con
    >>> root_dir = "root_dir"
    >>> wildcard = "*"
    >>> root_dir_wildcard = os.path.join(root_dir, wildcard)
    >>> entry_list = win32file.FindFilesW(root_dir_wildcard)
    >>> len(entry_list)  # Don't display the whole content as it's too long
    8
    >>> [entry[-2] for entry in entry_list]  # Only display the entry names
    ['.', '..', 'dir0', 'dir1', 'dir2', 'dir3', 'file0', 'file1']
    >>>
    >>> [entry[-2] for entry in entry_list if entry[0] & win32con.FILE_ATTRIBUTE_DIRECTORY and entry[-2] not in (".", "..")]  # Filter entries and only display dir names (except self and parent)
    ['dir0', 'dir1', 'dir2', 'dir3']
    >>>
    >>> [os.path.join(root_dir, entry[-2]) for entry in entry_list if entry[0] & (win32con.FILE_ATTRIBUTE_NORMAL | win32con.FILE_ATTRIBUTE_ARCHIVE)]  # Only display file "full" names
    ['root_dir\\file0', 'root_dir\\file1']

    Ghi chú :


  1. Cài đặt một số gói (bên thứ ba) khác thực hiện thủ thuật
    • Nhiều khả năng, sẽ dựa vào một (hoặc nhiều hơn) ở trên (có thể với các tùy chỉnh nhỏ)


Ghi chú :

  • Mã có nghĩa là di động (ngoại trừ những nơi nhắm mục tiêu đến một khu vực cụ thể - được đánh dấu) hoặc chéo:

    • nền tảng ( Nix , Win ,)
    • Phiên bản Python (2, 3,)
  • Nhiều kiểu đường dẫn (tuyệt đối, họ hàng) đã được sử dụng trên các biến thể trên, để minh họa thực tế là "công cụ" được sử dụng linh hoạt theo hướng này

  • os.listdiros.scandirsử dụng opendir / readdir / closir ( [MS.Docs]: Hàm FindFirstFileW / [MS.Docs]: Hàm FindNextFileW / [MS.Docs]: Hàm FindClose ) (thông qua [GitHub]: python / cpython - (master) Mô-đun / posixmodule.c )

  • win32file.FindFilesWcũng sử dụng các hàm ( Win cụ thể) đó (thông qua [GitHub]: mhammond / pywin32 - (master) pywin32 / win32 / src / win32file.i )

  • _get_dir_content (từ điểm # 1. ) có thể được triển khai bằng bất kỳ cách tiếp cận nào trong số này (một số sẽ yêu cầu nhiều công việc hơn và một số ít hơn)

    • Một số bộ lọc nâng cao (thay vì chỉ tập tin so với thư mục) có thể được thực hiện: ví dụ: đối số include_ Folders có thể được thay thế bằng một bộ lọc khác (ví dụ: bộ lọc_func ) sẽ là một hàm lấy một đường dẫn làm đối số: filter_func=lambda x: True(điều này không loại bỏ bất cứ điều gì) và bên trong _get_dir_content một cái gì đó như: if not filter_func(entry_with_path): continue(nếu chức năng không thành công cho một mục nhập, nó sẽ bị bỏ qua), nhưng mã càng phức tạp thì càng mất nhiều thời gian để thực thi
  • Đáng chú ý! Vì đệ quy được sử dụng, tôi phải đề cập rằng tôi đã thực hiện một số thử nghiệm trên máy tính xách tay của mình ( Win 10 x64 ), hoàn toàn không liên quan đến vấn đề này và khi mức đệ quy đạt đến các giá trị ở đâu đó trong phạm vi ( 990 .. 1000) ( đệ quy - 1000 (mặc định)), tôi đã có StackOverflow :). Nếu cây thư mục vượt quá giới hạn đó (tôi không phải là chuyên gia về FS , vì vậy tôi không biết liệu điều đó có khả thi hay không), đó có thể là một vấn đề.
    Tôi cũng phải đề cập rằng tôi đã không cố gắng tăng đệ quy vì tôi không có kinh nghiệm trong khu vực (tôi có thể tăng bao nhiêu trước khi phải tăng stack ở HĐHmức), nhưng trên lý thuyết sẽ luôn có khả năng thất bại, nếu độ sâu dir lớn hơn mức đệ quy cao nhất có thể (trên máy đó)

  • Các mẫu mã chỉ dành cho mục đích trình diễn. Điều đó có nghĩa là tôi đã không tính đến việc xử lý lỗi (tôi không nghĩ có bất kỳ lần thử / ngoại trừ / khác / cuối cùng ), vì vậy mã không mạnh mẽ (lý do là: giữ cho nó đơn giản và ngắn nhất có thể ). Đối với sản xuất , xử lý lỗi cũng nên được thêm vào

Các cách tiếp cận khác:

  1. Chỉ sử dụng Python làm trình bao bọc

    • Mọi thứ được thực hiện bằng cách sử dụng công nghệ khác
    • Công nghệ đó được gọi từ Python
    • Hương vị nổi tiếng nhất mà tôi biết là cách tôi gọi là phương pháp quản trị hệ thống :

      • Sử dụng Python (hoặc bất kỳ ngôn ngữ lập trình nào cho vấn đề đó) để thực thi các lệnh shell (và phân tích kết quả đầu ra của chúng)
      • Một số người coi đây là một hack gọn gàng
      • Tôi coi nó giống như một cách giải quyết khập khiễng ( gainarie ), vì hành động được thực hiện từ shell ( cmd trong trường hợp này), và do đó không liên quan gì đến Python .
      • Lọc ( grep/ findstr) hoặc định dạng đầu ra có thể được thực hiện ở cả hai bên, nhưng tôi sẽ không nhấn mạnh vào nó. Ngoài ra, tôi cố tình sử dụng os.systemthay vì subprocess.Popen.
      (py35x64_test) E:\Work\Dev\StackOverflow\q003207219>"e:\Work\Dev\VEnvs\py35x64_test\Scripts\python.exe" -c "import os;os.system(\"dir /b root_dir\")"
      dir0
      dir1
      dir2
      dir3
      file0
      file1

    Nói chung, cách tiếp cận này là cần tránh, vì nếu một số định dạng đầu ra lệnh hơi khác nhau giữa các phiên bản / hương vị của hệ điều hành , thì mã phân tích cũng phải được điều chỉnh; không đề cập đến sự khác biệt giữa các địa phương).


48

Tôi thực sự thích câu trả lời của adamk , đề nghị bạn sử dụng glob(), từ mô-đun cùng tên. Điều này cho phép bạn có mô hình khớp với *s.

Nhưng như những người khác đã chỉ ra trong các bình luận, glob()có thể bị vấp phải các hướng chém không nhất quán. Để giúp với điều đó, tôi khuyên bạn nên sử dụng join()và các expanduser()chức năng trong os.pathmô-đun, và có lẽ cả getcwd()chức năng trong osmô-đun.

Ví dụ:

from glob import glob

# Return everything under C:\Users\admin that contains a folder called wlp.
glob('C:\Users\admin\*\wlp')

Ở trên là khủng khiếp - đường dẫn đã được mã hóa cứng và sẽ chỉ hoạt động trên Windows giữa tên ổ đĩa và \s được mã hóa cứng vào đường dẫn.

from glob    import glob
from os.path import join

# Return everything under Users, admin, that contains a folder called wlp.
glob(join('Users', 'admin', '*', 'wlp'))

Ở trên hoạt động tốt hơn, nhưng nó phụ thuộc vào tên thư mục Usersthường thấy trên Windows và không thường thấy trên các HĐH khác. Nó cũng dựa vào người dùng có một tên cụ thể admin,.

from glob    import glob
from os.path import expanduser, join

# Return everything under the user directory that contains a folder called wlp.
glob(join(expanduser('~'), '*', 'wlp'))

Điều này hoạt động hoàn hảo trên tất cả các nền tảng.

Một ví dụ tuyệt vời khác hoạt động hoàn hảo trên các nền tảng và làm một cái gì đó hơi khác một chút:

from glob    import glob
from os      import getcwd
from os.path import join

# Return everything under the current directory that contains a folder called wlp.
glob(join(getcwd(), '*', 'wlp'))

Hy vọng những ví dụ này giúp bạn thấy sức mạnh của một vài chức năng bạn có thể tìm thấy trong các mô-đun thư viện Python tiêu chuẩn.


4
Thêm niềm vui toàn cầu: bắt đầu trong Python 3.5, **hoạt động miễn là bạn đặt recursive = True. Xem các tài liệu ở đây: docs.python.org/3.5/library/glob.html#glob.glob
ArtOfWarfare

36
def list_files(path):
    # returns a list of names (with extension, without full path) of all files 
    # in folder path
    files = []
    for name in os.listdir(path):
        if os.path.isfile(os.path.join(path, name)):
            files.append(name)
    return files 

cảm ơn! làm! hoàn hảo!
ambigus9

23

Nếu bạn đang tìm kiếm một triển khai tìm kiếm Python , đây là một công thức tôi sử dụng khá thường xuyên:

from findtools.find_files import (find_files, Match)

# Recursively find all *.sh files in **/usr/bin**
sh_files_pattern = Match(filetype='f', name='*.sh')
found_files = find_files(path='/usr/bin', match=sh_files_pattern)

for found_file in found_files:
    print found_file

Vì vậy, tôi đã tạo ra một gói PyPI từ đó và cũng có một kho GitHub . Tôi hy vọng rằng ai đó tìm thấy nó có khả năng hữu ích cho mã này.


14

Để có kết quả lớn hơn, bạn có thể sử dụng listdir()phương thức của osmô-đun cùng với trình tạo (trình tạo là trình lặp mạnh mẽ giữ trạng thái của nó, nhớ không?). Đoạn mã sau hoạt động tốt với cả hai phiên bản: Python 2 và Python 3.

Đây là một mã:

import os

def files(path):  
    for file in os.listdir(path):
        if os.path.isfile(os.path.join(path, file)):
            yield file

for file in files("."):  
    print (file)

Các listdir()phương thức trả về danh sách các mục cho các thư mục nhất định. Phương thức os.path.isfile()trả về Truenếu mục đã cho là một tệp. Và yieldtoán tử thoát khỏi func nhưng vẫn giữ trạng thái hiện tại và nó chỉ trả về tên của mục được phát hiện dưới dạng tệp. Tất cả những điều trên cho phép chúng ta lặp qua chức năng của trình tạo.


11

Trả về một danh sách các filepath tuyệt đối, không tái diễn thành các thư mục con

L = [os.path.join(os.getcwd(),f) for f in os.listdir('.') if os.path.isfile(os.path.join(os.getcwd(),f))]

2
Lưu ý: os.path.abspath(f)sẽ là một thay thế rẻ hơn cho os.path.join(os.getcwd(),f).
ShadowRanger

Tôi sẽ vẫn hiệu quả hơn nếu bạn bắt đầu cwd = os.path.abspath('.'), sau đó sử dụng cwdthay vì '.'os.getcwd()trong suốt để tránh vô số cuộc gọi hệ thống dư thừa.
Martijn Pieters

10
import os
import os.path


def get_files(target_dir):
    item_list = os.listdir(target_dir)

    file_list = list()
    for item in item_list:
        item_dir = os.path.join(target_dir,item)
        if os.path.isdir(item_dir):
            file_list += get_files(item_dir)
        else:
            file_list.append(item_dir)
    return file_list

Ở đây tôi sử dụng một cấu trúc đệ quy.


Điều tương tự có thể đạt được chỉ trong một dòng với pathlib:filter(Path.is_file, Path().rglob('*'))
Georgy

9

Một giáo viên thông thái đã nói với tôi một lần rằng:

Khi có một số cách được thiết lập để làm một cái gì đó, không có cách nào là tốt cho tất cả các trường hợp.

Do đó tôi sẽ thêm một giải pháp cho một tập hợp con của vấn đề: khá thường xuyên, chúng tôi chỉ muốn kiểm tra xem một tệp có khớp với chuỗi bắt đầu và chuỗi kết thúc hay không mà không đi vào thư mục con. Do đó, chúng tôi muốn một hàm trả về danh sách tên tệp, như:

filenames = dir_filter('foo/baz', radical='radical', extension='.txt')

Nếu bạn quan tâm đến việc khai báo hai hàm đầu tiên, điều này có thể được thực hiện:

def file_filter(filename, radical='', extension=''):
    "Check if a filename matches a radical and extension"
    if not filename:
        return False
    filename = filename.strip()
    return(filename.startswith(radical) and filename.endswith(extension))

def dir_filter(dirname='', radical='', extension=''):
    "Filter filenames in directory according to radical and extension"
    if not dirname:
        dirname = '.'
    return [filename for filename in os.listdir(dirname)
                if file_filter(filename, radical, extension)]

Giải pháp này có thể dễ dàng khái quát hóa bằng các biểu thức thông thường (và bạn có thể muốn thêm một patternđối số, nếu bạn không muốn các mẫu của mình luôn bám vào phần đầu hoặc phần cuối của tên tệp).


6

Sử dụng máy phát điện

import os
def get_files(search_path):
     for (dirpath, _, filenames) in os.walk(search_path):
         for filename in filenames:
             yield os.path.join(dirpath, filename)
list_files = get_files('.')
for filename in list_files:
    print(filename)

4

Một biến thể rất dễ đọc khác cho Python 3.4+ là sử dụng pathlib.Path.glob:

from pathlib import Path
folder = '/foo'
[f for f in Path(folder).glob('*') if f.is_file()]

Thật đơn giản để làm cho cụ thể hơn, ví dụ: chỉ tìm các tệp nguồn Python không phải là liên kết tượng trưng, ​​trong tất cả các thư mục con:

[f for f in Path(folder).glob('**/*.py') if not f.is_symlink()]

3

Đây là chức năng mục đích chung của tôi cho việc này. Nó trả về một danh sách các đường dẫn tệp chứ không phải tên tệp vì tôi thấy rằng nó hữu ích hơn. Nó có một vài đối số tùy chọn làm cho nó linh hoạt. Chẳng hạn, tôi thường sử dụng nó với các đối số như pattern='*.txt'hoặc subfolders=True.

import os
import fnmatch

def list_paths(folder='.', pattern='*', case_sensitive=False, subfolders=False):
    """Return a list of the file paths matching the pattern in the specified 
    folder, optionally including files inside subfolders.
    """
    match = fnmatch.fnmatchcase if case_sensitive else fnmatch.fnmatch
    walked = os.walk(folder) if subfolders else [next(os.walk(folder))]
    return [os.path.join(root, f)
            for root, dirnames, filenames in walked
            for f in filenames if match(f, pattern)]

2

Tôi sẽ cung cấp một lớp lót mẫu trong đó có thể cung cấp loại đường dẫn và loại tệp làm đầu vào. Mã này trả về một danh sách tên tệp có phần mở rộng csv. Sử dụng . trong trường hợp tất cả các tập tin cần phải được trả lại. Điều này cũng sẽ quét đệ quy các thư mục con.

[y for x in os.walk(sourcePath) for y in glob(os.path.join(x[0], '*.csv'))]

Sửa đổi phần mở rộng tập tin và đường dẫn nguồn khi cần thiết.


1
Nếu bạn sẽ sử dụng glob, sau đó chỉ cần sử dụng glob('**/*.csv', recursive=True). Không cần kết hợp điều này với os.walk()để lặp lại ( recursive**được hỗ trợ kể từ Python 3.5).
Martijn Pieters

2

Đối với python2: pip cài đặt rglob

import rglob
file_list=rglob.rglob("/home/base/dir/", "*")
print file_list

2

dircache là "Không dùng nữa kể từ phiên bản 2.6: Mô-đun dircache đã bị xóa trong Python 3.0."

import dircache
list = dircache.listdir(pathname)
i = 0
check = len(list[0])
temp = []
count = len(list)
while count != 0:
  if len(list[i]) != check:
     temp.append(list[i-1])
     check = len(list[i])
  else:
    i = i + 1
    count = count - 1

print temp

17
dirchache là "Không dùng nữa kể từ phiên bản 2.6: Mô-đun dircache đã bị xóa trong Python 3.0."
Daniel Reis
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.