Bagaimana cara mendaftar semua file direktori?


Jawaban:


4216

os.listdir()akan memberi Anda semua yang ada di direktori - file dan direktori .

Jika Anda hanya ingin file, Anda bisa memfilter ini menggunakan os.path:

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

atau Anda bisa menggunakan os.walk()yang akan menghasilkan dua daftar untuk setiap direktori yang dikunjungi - membaginya menjadi file dan dir untuk Anda. Jika Anda hanya menginginkan direktori teratas, Anda bisa memecahnya saat pertama kali menghasilkan

from os import walk

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

87
Sedikit lebih sederhana: (_, _, filenames) = walk(mypath).next() (jika Anda yakin bahwa jalan akan mengembalikan setidaknya satu nilai, yang seharusnya.)
misterbee

9
Sedikit modifikasi untuk menyimpan path lengkap: untuk (dirpath, dirnames, nama file) di os.walk (mypath): checksum_files.extend (os.path.join (dirpath, nama file) untuk nama file dalam nama file) break
okigan

150
f.extend(filenames)sebenarnya tidak sama dengan f = f + filenames. extendakan memodifikasi fdi tempat, sedangkan menambahkan membuat daftar baru di lokasi memori baru. Ini berarti extendumumnya lebih efisien daripada +, tetapi kadang-kadang dapat menyebabkan kebingungan jika beberapa objek menyimpan referensi ke daftar. Terakhir, perlu dicatat bahwa f += filenamesitu setara dengan f.extend(filenames), bukan f = f + filenames .
Benjamin Hodgson

30
@ maisterbee, solusi Anda adalah yang terbaik, hanya satu perbaikan kecil:_, _, filenames = next(walk(mypath), (None, None, []))
bgusach

35
dalam penggunaan python 3.x(_, _, filenames) = next(os.walk(mypath))
ET-CS

1683

Saya lebih suka menggunakan globmodul, seperti halnya pencocokan pola dan ekspansi.

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

Ini akan mengembalikan daftar dengan file yang diminta:

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

17
itu cara pintas untuk listdir + fnmatch docs.python.org/library/fnmatch.html#fnmatch.fnmatch
Stefano

31
untuk memperjelas, ini tidak mengembalikan "path lengkap"; ia hanya mengembalikan ekspansi gumpal, apa pun itu. Misalnya, diberikan /home/user/foo/bar/hello.txt, maka, jika berjalan di direktori foo, glob("bar/*.txt")akan kembali bar/hello.txt. Ada beberapa kasus ketika Anda benar-benar menginginkan jalur penuh (yaitu absolut); untuk kasus-kasus tersebut, lihat stackoverflow.com/questions/51520/…
michael

1
Terkait: temukan file secara rekursif dengan glob: stackoverflow.com/a/2186565/4561887
Gabriel Staples

6
tidak menjawab pertanyaan ini. glob.glob("*")akan.
Jean-François Fabre

Cantik!!!! jadi .... x=glob.glob("../train/*.png")akan memberi saya array jalur saya, selama saya tahu nama foldernya. Keren abis!
Jennifer Crosby

860

Dapatkan daftar file dengan Python 2 dan 3


os.listdir()

Cara mendapatkan semua file (dan direktori) di direktori saat ini (Python 3)

Berikut ini, adalah metode sederhana untuk mengambil hanya file di direktori saat ini, menggunakan os dan listdir()fungsinya, dalam Python 3. Eksplorasi lebih lanjut, akan menunjukkan cara mengembalikan folder di direktori, tetapi Anda tidak akan memiliki file di subdirektori, untuk itu Anda bisa menggunakan jalan - bahas nanti).

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

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

glob

Saya menemukan glob lebih mudah untuk memilih file dengan tipe yang sama atau dengan sesuatu yang sama. Lihatlah contoh berikut:

import glob

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

glob dengan pemahaman daftar

import glob

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

glob dengan suatu fungsi

Fungsi mengembalikan daftar ekstensi yang diberikan (.txt, .docx ecc.) Dalam argumen

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 memperpanjang kode sebelumnya

Fungsi sekarang mengembalikan daftar file yang cocok dengan string yang Anda berikan sebagai argumen

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)}")

keluaran

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

Mendapatkan nama jalur lengkap dengan os.path.abspath

Seperti yang Anda perhatikan, Anda tidak memiliki path lengkap file dalam kode di atas. Jika Anda perlu memiliki path absolut, Anda dapat menggunakan fungsi lain dari os.pathmodul yang disebut _getfullpathname, menempatkan file yang Anda dapatkan os.listdir()sebagai argumen. Ada cara lain untuk memiliki path lengkap, seperti yang akan kita periksa nanti (saya ganti, seperti yang disarankan oleh mexmex, dengan _getfullpathname 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']

Dapatkan nama path lengkap dari jenis file ke semua subdirektori dengan walk

Saya menemukan ini sangat berguna untuk menemukan barang di banyak direktori, dan itu membantu saya menemukan file yang saya tidak ingat namanya:

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(): dapatkan file di direktori saat ini (Python 2)

Dalam Python 2, jika Anda ingin daftar file di direktori saat ini, Anda harus memberikan argumen sebagai '.' atau os.getcwd () dalam metode os.listdir.

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

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

Untuk naik di pohon direktori

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

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

Dapatkan file: os.listdir()di direktori tertentu (Python 2 dan 3)

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

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

Dapatkan file dari subdirektori tertentu dengan os.listdir()

import os

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

os.walk('.') - direktori saat ini

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

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

next(os.walk('.')) dan 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:\\') - dapatkan path lengkap - daftar pemahaman

 [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 - dapatkan path lengkap - semua file dalam subdirektori **

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() - dapatkan hanya file txt

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

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

Menggunakan globuntuk mendapatkan path lengkap file

Jika saya perlu path absolut dari file:

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

Menggunakan os.path.isfileuntuk menghindari direktori dalam daftar

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']

Menggunakan pathlibdari 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

Dengan list comprehension:

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

Atau, gunakan pathlib.Path()sebagai gantipathlib.Path(".")

Gunakan metode glob di pathlib.Path ()

import pathlib

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

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

Dapatkan semua dan hanya file dengan 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']

Dapatkan hanya file dengan langkah berikutnya dan berjalan di direktori

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

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

Dapatkan hanya direktori dengan yang berikutnya dan berjalan di direktori

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

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

Dapatkan semua nama subdir 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() dari Python 3.5 dan lebih tinggi

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

Contoh:

Ex. 1: Berapa banyak file yang ada di subdirektori?

Dalam contoh ini, kami mencari jumlah file yang termasuk dalam semua direktori dan subdirektori.

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'

Contoh.2: Bagaimana cara menyalin semua file dari direktori ke direktori lain?

Sebuah skrip untuk membuat pesanan di komputer Anda menemukan semua file dari jenis (default: pptx) dan menyalinnya di folder baru.

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

Ex. 3: Cara mendapatkan semua file dalam file txt

Jika Anda ingin membuat file txt dengan semua nama file:

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

Contoh: txt dengan semua file hard drive

"""
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")

Semua file C: \ dalam satu file teks

Ini adalah versi lebih pendek dari kode sebelumnya. Ubah folder tempat mulai mencari file jika Anda perlu memulai dari posisi lain. Kode ini menghasilkan 50 mb pada file teks di komputer saya dengan sesuatu yang kurang dari 500.000 baris dengan file dengan path lengkap.

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")

Cara menulis file dengan semua jalur dalam folder jenis

Dengan fungsi ini Anda dapat membuat file txt yang akan memiliki nama jenis file yang Anda cari (mis. Pngfile.txt) dengan semua path lengkap semua file jenis itu. Kadang-kadang bisa bermanfaat, saya pikir.

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

(Baru) Temukan semua file dan buka dengan tkinter GUI

Saya hanya ingin menambahkan di 2019 ini aplikasi kecil untuk mencari semua file dalam sebuah dir dan dapat membukanya dengan menggandakan pada nama file dalam daftar. masukkan deskripsi gambar di sini

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
Ini adalah mish-mash dari terlalu banyak jawaban untuk pertanyaan yang tidak diajukan di sini. Mungkin juga layak untuk menjelaskan apa peringatan atau pendekatan yang disarankan. Saya tidak lebih baik mengetahui satu cara versus 20 cara untuk melakukan hal yang sama kecuali saya juga tahu mana yang lebih tepat untuk digunakan saat itu.
cs95

Ok, ASAP saya akan melihat jawaban saya dan mencoba membuatnya lebih bersih dan dengan informasi yang lebih berguna tentang perbedaan antara metode dll.
Giovanni G. PY

Anda seharusnya tidak menentukan ekstensi file dengan memeriksa apakah nama file mengandung substring. Itu mungkin menyebabkan banyak masalah. Saya sarankan untuk selalu memeriksa apakah nama file berakhir dengan substring tertentu.
ni1ight

Oke, @ n1light, saya mengubah kode ...
Giovanni G. PY

812
import os
os.listdir("somedirectory")

akan mengembalikan daftar semua file dan direktori di "direktori tertentu".


11
Ini mengembalikan path relatif file, dibandingkan dengan path lengkap dikembalikan olehglob.glob
xji

22
@ JIXiang: os.listdir()selalu mengembalikan nama file belaka (bukan jalur relatif). Apa yang glob.glob()dikembalikan didorong oleh format jalur dari pola input.
mklement0

os.listdir () -> Selalu daftar direktori dan file di dalam lokasi yang disediakan. Apakah ada cara untuk mendaftar hanya direktori bukan file?
RonyA

160

Solusi satu baris untuk mendapatkan hanya daftar file (tanpa subdirektori):

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

atau nama path absolut:

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

7
Hanya satu liner jika Anda sudah melakukannya import os. Tampak kurang ringkas daripada glob()bagi saya.
ArtOfWarfare

4
masalah dengan glob adalah bahwa folder bernama 'something.something' akan dikembalikan oleh glob ('/ home / adam /*.*')
Remi

6
Pada OS X, ada sesuatu yang disebut bundel. Ini adalah direktori yang umumnya harus diperlakukan sebagai file (seperti .tar). Apakah Anda ingin yang diperlakukan sebagai file atau direktori? Menggunakan glob()akan memperlakukannya sebagai file. Metode Anda akan memperlakukannya sebagai direktori.
ArtOfWarfare

132

Mendapatkan Path File Lengkap Dari Direktori dan Semua Subdirektorinya

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")

  • Path yang saya berikan pada fungsi di atas berisi 3 file — dua di antaranya di direktori root, dan yang lain di subfolder yang disebut "SUBFOLDER." Anda sekarang dapat melakukan hal-hal seperti:
  • print full_file_paths yang akan mencetak daftar:

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

Jika mau, Anda dapat membuka dan membaca konten, atau hanya fokus pada file dengan ekstensi ".dat" seperti pada kode di bawah ini:

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

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


Ini adalah satu-satunya jawaban.
pelajar

78

Karena versi 3.4 ada iterator bawaan untuk ini yang jauh lebih efisien daripada os.listdir():

pathlib: Baru dalam versi 3.4.

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

Menurut PEP 428 , tujuan pathlibperpustakaan adalah untuk menyediakan hirarki kelas sederhana untuk menangani jalur sistem file dan operasi umum yang dilakukan pengguna atas mereka.

os.scandir(): Baru dalam versi 3.5.

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

Perhatikan bahwa os.walk()penggunaan os.scandir()bukan os.listdir()dari versi 3.5, dan kecepatannya meningkat 2-20 kali menurut PEP 471 .

Izinkan saya juga merekomendasikan membaca komentar ShadowRanger di bawah ini.


1
Terima kasih! Saya pikir ini adalah satu-satunya solusi yang tidak mengembalikan secara langsung a list. Bisa digunakan p.namedaripada yang pertama sebagai palternatif jika lebih disukai.
jeromej

1
Selamat datang! Saya lebih suka membuat pathlib.Path()instance karena mereka memiliki banyak metode yang berguna saya tidak ingin membuang-buang limbah. Anda juga dapat memanggil str(p)mereka untuk nama jalur.
SzieberthAdam

6
Catatan: os.scandirSolusinya akan lebih efisien daripada os.listdirdengan os.path.is_filecek atau sejenisnya, bahkan jika Anda memerlukan list(sehingga Anda tidak mendapat manfaat dari iterasi malas), karena os.scandirmenggunakan API yang disediakan OS yang memberi Anda is_fileinformasi secara gratis karena iterates , tidak ada per-file round trip ke disk untuk statmereka sama sekali (pada Windows, DirEntrys membuat Anda lengkap statinformasi gratis, pada sistem NIX * perlu statuntuk info luar is_file, is_dir, dll, tapi DirEntrycache pada pertama statuntuk kenyamanan).
ShadowRanger

1
Anda juga dapat menggunakan entry.nameuntuk mendapatkan hanya nama file, atau entry.pathuntuk mendapatkan path lengkapnya. Tidak ada lagi os.path.join () di semua tempat.
user136036

56

Catatan awal

  • Meskipun ada perbedaan yang jelas antara istilah file dan direktori dalam teks pertanyaan, beberapa orang mungkin berpendapat bahwa direktori sebenarnya adalah file khusus
  • Pernyataan: " semua file direktori " dapat diartikan dalam dua cara:
    1. Semua keturunan langsung (atau level 1) saja
    2. Semua keturunan di seluruh pohon direktori (termasuk yang ada di sub-direktori)
  • Ketika pertanyaan diajukan, saya membayangkan bahwa Python 2 , adalah versi LTS , namun sampel kode akan dijalankan oleh Python 3 ( .5 ) (saya akan membiarkannya sesuai dengan Python 2 ; mungkin juga, kode apa pun yang dimiliki oleh Python yang akan saya posting, berasal dari v3.5.4 - kecuali ditentukan lain). Itu memiliki konsekuensi yang terkait dengan kata kunci lain dalam pertanyaan: " tambahkan mereka ke dalam daftar ":

    • Di pra versi Python 2.2 , urutan (iterables) sebagian besar diwakili oleh daftar (tupel, set, ...)
    • Dalam Python 2.2 , konsep generator ( [Python.Wiki]: Generator ) - milik [Python 3]: Pernyataan hasil ) - diperkenalkan. Seiring berjalannya waktu, generator mulai muncul untuk fungsi-fungsi yang kembali / bekerja dengan daftar
    • Dalam Python 3 , generator adalah perilaku default
    • Tidak yakin apakah mengembalikan daftar masih wajib (atau generator juga akan melakukannya), tetapi meneruskan generator ke daftar konstruktor, akan membuat daftar dari daftar itu (dan juga mengkonsumsinya). Contoh di bawah ini mengilustrasikan perbedaan pada [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'>)
  • Contoh-contoh akan didasarkan pada direktori bernama root_dir dengan struktur berikut (contoh ini untuk Win , tapi saya juga menggunakan pohon yang sama di 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


Solusi

Pendekatan terprogram:

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

    Kembali daftar yang berisi nama-nama entri dalam direktori yang diberikan oleh path. Daftar ini dalam urutan acak, dan tidak termasuk entri khusus '.'dan '..'...


    >>> 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']

    Contoh yang lebih rumit ( 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()

    Catatan :

    • Ada dua implementasi:
      • Yang menggunakan generator (tentu saja di sini sepertinya tidak berguna, karena saya segera mengonversi hasilnya menjadi daftar)
      • Yang klasik (nama fungsi berakhiran _old )
    • Rekursi digunakan (untuk masuk ke subdirektori)
    • Untuk setiap implementasi ada dua fungsi:
      • Yang dimulai dengan garis bawah ( _ ): "pribadi" (tidak boleh dipanggil secara langsung) - yang melakukan semua pekerjaan
      • Yang publik (bungkus lebih dari sebelumnya): itu hanya menghapus jalur awal (jika diperlukan) dari entri yang dikembalikan. Ini adalah implementasi yang jelek, tapi itu satu-satunya ide yang bisa saya dapatkan pada saat ini
    • Dalam hal kinerja, generator umumnya sedikit lebih cepat (mempertimbangkan waktu pembuatan dan iterasi ), tetapi saya tidak mengujinya dalam fungsi rekursif, dan juga saya beralih ke fungsi di dalam generator bagian dalam - tidak tahu bagaimana kinerja ramah itu
    • Bermainlah dengan argumen untuk mendapatkan hasil yang berbeda


    Keluaran :

    (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 )

    Mengembalikan iterator objek os.DirEntry yang sesuai dengan entri dalam direktori yang diberikan oleh path . Entri dihasilkan dalam urutan acak, dan entri khusus '.'dan '..'tidak termasuk.

    Menggunakan scandir () sebagai ganti listdir () dapat secara signifikan meningkatkan kinerja kode yang juga memerlukan tipe file atau informasi atribut file, karena objek os.DirEntry memaparkan informasi ini jika sistem operasi menyediakannya ketika memindai direktori. Semua metode os.DirEntry dapat melakukan panggilan sistem, tetapi is_dir () dan is_file () biasanya hanya memerlukan panggilan sistem untuk tautan simbolik; os.DirEntry.stat () selalu memerlukan panggilan sistem di Unix tetapi hanya membutuhkan satu untuk tautan simbolis pada 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

    Catatan :

    • Ini mirip dengan os.listdir
    • Tetapi juga lebih fleksibel (dan menawarkan lebih banyak fungsi), lebih banyak Python ic (dan dalam beberapa kasus, lebih cepat)


  1. [Python 3]: os. walk ( top, topdown = Benar, onerror = Tidak ada, followlinks = Salah )

    Hasilkan nama file di pohon direktori dengan berjalan pohon itu dari atas ke bawah atau dari bawah ke atas. Untuk setiap direktori dalam pohon berakar di direktori atas (termasuk atas sendiri), itu menghasilkan 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', [], [])

    Catatan :

    • Di bawah layar, ia menggunakan os.scandir( os.listdirpada versi yang lebih lama)
    • Itu mengangkat berat dengan berulang di subfolder


  1. [Python 3]: glob. glob ( pathname, *, recursive = False ) ( [Python 3]: glob. iglob ( pathname, *, recursive = False ) )

    Kembalikan daftar nama path yang mungkin kosong yang cocok dengan pathname , yang harus berupa string yang berisi spesifikasi path. pathname bisa berupa absolut (suka /usr/src/Python-1.5/Makefile) atau relatif (suka ../../Tools/*/*.gif), dan dapat berisi wildcard gaya-shell. Symlinks yang rusak termasuk dalam hasil (seperti dalam shell).
    ...
    Berubah dalam versi 3.5 : Dukungan untuk gumpalan rekursif menggunakan " **".


    >>> 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

    Catatan :

    • Penggunaan os.listdir
    • Untuk pohon besar (terutama jika rekursif aktif), iglob lebih disukai
    • Mengizinkan pemfilteran lanjutan berdasarkan nama (karena wildcard)


  1. [Python 3]: class pathlib. Path ( * pathsegments ) ( 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']

    Catatan :

    • Ini adalah salah satu cara untuk mencapai tujuan kami
    • Ini adalah gaya jalur penanganan OOP
    • Menawarkan banyak fungsi


  1. [Python 2]: dircache.listdir (path) ( hanya 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]: CLOSEDIR (3) via [Python 3]: ctypes - Pustaka fungsi asing untuk Python ( spesifik POSIX )

    ctypes adalah pustaka fungsi asing untuk Python. Ini menyediakan tipe data yang kompatibel C, dan memungkinkan fungsi panggilan di DLL atau perpustakaan bersama. Ini dapat digunakan untuk membungkus pustaka ini dengan Python murni.

    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()

    Catatan :

    • Itu memuat tiga fungsi dari libc (dimuat dalam proses saat ini) dan memanggil mereka (untuk lebih jelasnya periksa [SO]: Bagaimana cara memeriksa apakah file ada tanpa pengecualian? (Jawaban @ CristiFati) - catatan terakhir dari item # 4. ). Yang akan menempatkan pendekatan ini sangat dekat dengan Python / C tepi
    • LinuxDirent64 adalah representasi ctypes dari struct dirent64 dari [man7]: dirent.h (0P) (demikian juga konstanta DT_ ) dari mesin saya: Ubtu 16 x64 ( 4.10.0-40-generik dan libc6-dev: amd64 ). Pada rasa / versi lain, definisi struct mungkin berbeda, dan jika demikian, alias ctypes harus diperbarui, jika tidak maka akan menghasilkan Perilaku Tidak Terdefinisi
    • Ini mengembalikan data dalam os.walkformat. Saya tidak repot untuk membuatnya rekursif, tetapi mulai dari kode yang ada, itu akan menjadi tugas yang cukup sepele
    • Semuanya bisa dilakukan pada Win juga, data (perpustakaan, fungsi, struct, konstanta, ...) berbeda


    Keluaran :

    [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 ( Win spesifik)

    Mengambil daftar nama file yang cocok, menggunakan Windows Unicode API. Antarmuka ke fungsi FindFirstFileW API / FindNextFileW / Find close.


    >>> 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']

    Catatan :


  1. Instal beberapa (pihak lain) paket pihak ketiga yang melakukan trik
    • Kemungkinan besar, akan bergantung pada satu (atau lebih) hal di atas (mungkin dengan sedikit penyesuaian)


Catatan :

  • Kode dimaksudkan untuk portabel (kecuali tempat yang menargetkan area tertentu - yang ditandai) atau tanda silang:

    • platform ( Nix , Win ,)
    • Versi python (2, 3,)
  • Berbagai gaya jalur (absolut, kerabat) digunakan di seluruh varian di atas, untuk menggambarkan fakta bahwa "alat" yang digunakan fleksibel dalam arah ini

  • os.listdirdan os.scandirgunakan opendir / readdir / closedir ( [MS.Docs]: Fungsi FindFirstFileW / [MS.Docs]: Fungsi FindNextFileW / [MS.Docs]: Fungsi FindClose ) (melalui [GitHub]: python / cpython - (master) cpython / Modul / posixmodule.c )

  • win32file.FindFilesWmenggunakan fungsi-fungsi ( spesifik Menang ) juga (melalui [GitHub]: mhammond / pywin32 - (master) pywin32 / win32 / src / win32file.i )

  • _get_dir_content (dari titik # 1. ) dapat diimplementasikan menggunakan salah satu dari pendekatan ini (beberapa akan membutuhkan lebih banyak pekerjaan dan beberapa lagi kurang)

    • Beberapa pemfilteran tingkat lanjut (alih-alih hanya file vs. dir) dapat dilakukan: misalnya argumen include_folders dapat diganti dengan yang lain (mis. Filter_func ) yang akan menjadi fungsi yang mengambil lintasan sebagai argumen: filter_func=lambda x: True(ini tidak menghapus apapun) dan di dalam _get_dir_content sesuatu seperti: if not filter_func(entry_with_path): continue(jika fungsi gagal untuk satu entri, itu akan dilewati), tetapi semakin kompleks kodenya, semakin lama waktu yang diperlukan untuk mengeksekusi
  • Nota bene! Karena rekursi digunakan, saya harus menyebutkan bahwa saya melakukan beberapa tes pada laptop saya ( Win 10 x64 ), sama sekali tidak terkait dengan masalah ini, dan ketika tingkat rekursi mencapai nilai di suatu tempat dalam kisaran (990 .. 1000) ( recursionlimit - 1000 (default)), saya dapat StackOverflow :). Jika pohon direktori melebihi batas itu (saya bukan ahli FS , jadi saya tidak tahu apakah itu mungkin), itu bisa menjadi masalah.
    Saya juga harus menyebutkan bahwa saya tidak mencoba meningkatkan rekursi karena saya tidak punya pengalaman di area tersebut (berapa banyak yang bisa saya tingkatkan sebelum harus juga menambah tumpukan di OSlevel), tetapi secara teori akan selalu ada kemungkinan kegagalan, jika kedalaman dir lebih besar dari batas rekursi tertinggi yang dimungkinkan (pada mesin itu)

  • Sampel kode hanya untuk tujuan demonstratif. Itu berarti bahwa saya tidak mempertimbangkan penanganan kesalahan akun (saya tidak berpikir ada coba / kecuali / lain / akhirnya blokir), jadi kodenya tidak kuat (alasannya adalah: membuatnya sesederhana dan sesingkat mungkin ). Untuk produksi , penanganan kesalahan harus ditambahkan juga

Pendekatan lain:

  1. Gunakan Python hanya sebagai pembungkus

    • Semuanya dilakukan dengan menggunakan teknologi lain
    • Teknologi itu dipanggil dari Python
    • Rasa paling terkenal yang saya tahu adalah apa yang saya sebut pendekatan administrator sistem :

      • Gunakan Python (atau bahasa pemrograman apa pun) untuk menjalankan perintah shell (dan uraikan hasilnya)
      • Beberapa menganggap ini hack yang rapi
      • Saya menganggapnya lebih seperti solusi lumpuh ( gainarie ), karena tindakan per se dilakukan dari shell ( cmd dalam kasus ini), dan dengan demikian tidak ada hubungannya dengan Python .
      • Pemfilteran ( grep/ findstr) atau pemformatan keluaran bisa dilakukan di kedua sisi, tapi saya tidak akan memaksanya. Juga, saya sengaja digunakan os.systemsebagai pengganti 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

    Secara umum pendekatan ini harus dihindari, karena jika beberapa format output perintah sedikit berbeda antara versi OS / rasa, kode parsing harus disesuaikan juga; belum lagi perbedaan antar lokal).


48

Saya sangat menyukai jawaban Adam , menyarankan agar Anda menggunakan glob(), dari modul dengan nama yang sama. Ini memungkinkan Anda memiliki pola yang cocok dengan *s.

Tetapi seperti yang orang lain tunjukkan dalam komentar, glob()bisa tersandung oleh arah garis miring yang tidak konsisten. Untuk membantu dengan itu, saya sarankan Anda menggunakan join()dan expanduser()fungsi dalam os.pathmodul, dan mungkin juga getcwd()fungsi dalam osmodul.

Sebagai contoh:

from glob import glob

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

Di atas mengerikan - path telah di-hardcode dan hanya akan bekerja di Windows antara nama drive dan yang \sedang di-hardcod ke path.

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'))

Di atas berfungsi lebih baik, tetapi bergantung pada nama folder Usersyang sering ditemukan di Windows dan tidak begitu sering ditemukan di OS lain. Itu juga bergantung pada pengguna yang memiliki nama tertentu 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'))

Ini berfungsi dengan baik di semua platform.

Contoh hebat lainnya yang bekerja sempurna di seluruh platform dan melakukan sesuatu yang sedikit berbeda:

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'))

Semoga contoh-contoh ini membantu Anda melihat kekuatan beberapa fungsi yang dapat Anda temukan di modul library Python standar.


4
Extra glob fun: dimulai dengan Python 3.5, **berfungsi selama Anda mengatur recursive = True. Lihat dokumen di sini: 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 

Terima kasih! bekerja! sempurna!
ambigus9

23

Jika Anda mencari implementasi Python find , ini adalah resep yang saya gunakan agak sering:

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

Jadi saya membuat paket PyPI darinya dan ada juga repositori GitHub . Saya harap seseorang menemukannya berpotensi berguna untuk kode ini.


14

Untuk hasil yang lebih besar, Anda dapat menggunakan listdir()metode osmodul bersama dengan generator (generator adalah iterator kuat yang mempertahankan kondisinya, ingat?). Kode berikut berfungsi dengan baik dengan kedua versi: Python 2 dan Python 3.

Ini kode:

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)

The listdir()Metode mengembalikan daftar entri untuk direktori yang diberikan. Metode os.path.isfile()kembali Truejika entri yang diberikan adalah file. Dan yieldoperator berhenti dari func tetapi tetap pada kondisi saat ini, dan hanya mengembalikan nama entri yang terdeteksi sebagai file. Semua hal di atas memungkinkan kita untuk mengulang fungsi generator.


11

Mengembalikan daftar filepath absolut, tidak berulang ke subdirektori

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

2
Catatan: os.path.abspath(f)akan menjadi pengganti yang agak lebih murah untuk os.path.join(os.getcwd(),f).
ShadowRanger

Aku akan lebih efisien lagi jika Anda mulai dengan cwd = os.path.abspath('.'), kemudian digunakan cwdsebagai pengganti '.'dan os.getcwd()seluruh beban menghindari panggilan sistem berlebihan.
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

Di sini saya menggunakan struktur rekursif.


Hal yang sama dapat dicapai hanya dalam satu baris dengan pathlib:filter(Path.is_file, Path().rglob('*'))
Georgy

9

Seorang guru yang bijak memberi tahu saya bahwa:

Ketika ada beberapa cara mapan untuk melakukan sesuatu, tidak ada satupun yang baik untuk semua kasus.

Saya kemudian akan menambahkan solusi untuk subset masalah: cukup sering, kami hanya ingin memeriksa apakah file cocok dengan string awal dan string akhir, tanpa masuk ke subdirektori. Karena itu kami ingin fungsi yang mengembalikan daftar nama file, seperti:

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

Jika Anda ingin mendeklarasikan dua fungsi, ini dapat dilakukan:

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)]

Solusi ini dapat dengan mudah digeneralisasikan dengan ekspresi reguler (dan Anda mungkin ingin menambahkan patternargumen, jika Anda tidak ingin pola Anda selalu menempel pada awal atau akhir nama file).


6

Menggunakan generator

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

Varian lain yang sangat mudah dibaca untuk Python 3.4+ adalah menggunakan pathlib.Path.glob:

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

Sangat mudah untuk membuat lebih spesifik, misalnya hanya mencari file sumber Python yang bukan tautan simbolik, juga di semua subdirektori:

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

3

Inilah fungsi tujuan umum saya untuk ini. Ini mengembalikan daftar path file daripada nama file karena saya menemukan itu lebih bermanfaat. Ini memiliki beberapa argumen opsional yang membuatnya serbaguna. Misalnya, saya sering menggunakannya dengan argumen seperti pattern='*.txt'atau 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

Saya akan memberikan sampel satu liner di mana sourcepath dan tipe file dapat diberikan sebagai input. Kode mengembalikan daftar nama file dengan ekstensi csv. Gunakan . seandainya semua file perlu dikembalikan. Ini juga akan memindai subdirektori secara rekursif.

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

Ubah ekstensi file dan jalur sumber sesuai kebutuhan.


1
Jika Anda akan menggunakan glob, maka gunakan saja glob('**/*.csv', recursive=True). Tidak perlu menggabungkan ini dengan os.walk()untuk berulang ( recursivedan **didukung sejak Python 3.5).
Martijn Pieters

2

Untuk python2: pip instal rglob

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

2

dircache adalah "Tidak digunakan sejak versi 2.6: Modul dircache telah dihapus di 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 adalah "Tidak digunakan sejak versi 2.6: Modul dircache telah dihapus di Python 3.0."
Daniel Reis
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.