Як перерахувати всі файли каталогу?


3473

Як я можу перерахувати всі файли каталогу в Python і додати їх до а list?


Відповіді:


4208

os.listdir()отримає все, що є в каталозі - файли та каталоги .

Якщо ви хочете лише файли, ви можете їх відфільтрувати за допомогою os.path:

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

або ви могли б використовувати , os.walk()які будуть давати два списки для кожного каталогу , то воно відвідувань - розбиття на файли і директорії для вас. Якщо ви хочете лише вгоріший каталог, ви можете просто зламати перший раз, коли він видається

from os import walk

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

87
Трохи простіше: (_, _, filenames) = walk(mypath).next() (якщо ви впевнені, що прогулянка поверне хоча б одне значення, яке воно повинно бути)
misterbee

9
Незначна модифікація для збереження повних шляхів: для (dirpath, dirnames, найменування файлів) в os.walk (mypath): Checkum_files.extend (os.path.join (dirpath, ім'я файлу) для імені файлу у назви файлів) break
okigan

150
f.extend(filenames)насправді не рівнозначний f = f + filenames. extendзмінить fна місці, тоді як додавання створює новий список у новому місці пам'яті. Це означає, що, extendяк правило, ефективніше +, але іноді може призвести до плутанини, якщо кілька об'єктів містять посилання на список. Нарешті, варто зазначити, що f += filenamesрівнозначно f.extend(filenames), ні f = f + filenames .
Бенджамін Ходжсон

30
@misterbee, ваше рішення найкраще, лише одне невелике поліпшення:_, _, filenames = next(walk(mypath), (None, None, []))
bgusach

35
у використанні python 3.x(_, _, filenames) = next(os.walk(mypath))
ET-CS

1680

Я вважаю за краще використовувати globмодуль, так як це відповідає узгодженню та розширенню.

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

Він поверне список із запитуваними файлами:

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

17
це ярлик для listdir + fnmatch docs.python.org/library/fnmatch.html#fnmatch.fnmatch
Стефано

31
щоб уточнити, це не повертає "повний шлях"; це просто повертає розширення глобуса, яким би воно не було. Напр., Дається /home/user/foo/bar/hello.txt, тоді, якщо працює в каталозі foo, glob("bar/*.txt")заповіт повернеться bar/hello.txt. Бувають випадки, коли ви насправді хочете повний (тобто абсолютний) шлях; про ці випадки див. stackoverflow.com/questions/51520/…
michael

1
Пов’язано: пошук файлів рекурсивно з глобусом: stackoverflow.com/a/2186565/4561887
Габріель Степлес

6
не відповідає на це запитання. glob.glob("*")би.
Жан-Франсуа Фабре

гарний!!!! так що .... x=glob.glob("../train/*.png")дасть мені масив моїх шляхів, поки я знаю назву папки. Так кльово!
Дженніфер Кросбі

857

Отримайте список файлів із Python 2 та 3


os.listdir()

Як отримати всі файли (та каталоги) у поточному каталозі (Python 3)

Далі наведені прості методи для отримання лише файлів у поточному каталозі, використовуючи os та listdir()функцію, в Python 3. Подальше дослідження продемонструє, як повертати папки в каталог, але у вас не буде файлу у підкаталозі, для цього ви можна використовувати прогулянку - обговорено пізніше).

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

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

glob

Я знайшов глобусом простіше вибрати файл одного типу або щось спільне. Подивіться на наступний приклад:

import glob

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

glob зі списком розуміння

import glob

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

glob з функцією

Функція повертає список даного розширення (.txt, .docx ecc.) В аргументі

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 розширення попереднього коду

Тепер функція повертає список файлів, які співпадають із рядком, який ви передаєте як аргумент

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

вихід

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

Отримання повної назви шляху за допомогою os.path.abspath

Як ви помітили, у вас немає повного шляху до файлу у наведеному вище коді. Якщо вам потрібен абсолютний шлях, ви можете скористатися іншою функцією os.pathмодуля, що називається _getfullpathname, поставивши файл, який ви отримаєте, os.listdir()як аргумент. Є й інші способи провести повний шлях, як ми перевіримо пізніше (я замінив, як запропонував mexmex, _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']

Отримайте повне ім'я шляху файлу до всіх підкаталогів walk

Я вважаю це дуже корисним для пошуку матеріалів у багатьох каталогах, і це допомогло мені знайти файл, про який я не запам'ятав ім'я:

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(): отримання файлів у поточному каталозі (Python 2)

У Python 2, якщо ви хочете, щоб список файлів у поточному каталозі, ви повинні навести аргумент як "." або os.getcwd () у методі os.listdir.

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

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

Щоб перейти в дерево каталогів

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

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

Отримання файлів: os.listdir()у певному каталозі (Python 2 та 3)

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

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

Отримайте файли певного підкаталогу os.listdir()

import os

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

os.walk('.') - поточний каталог

 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:\\') - отримати повний шлях - перелічити розуміння

 [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 - отримати повний шлях - всі файли в підручниках **

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() - отримуйте лише файли txt

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

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

Використовується globдля отримання повного шляху до файлів

Якщо мені знадобиться абсолютний шлях до файлів:

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

Використовуючи os.path.isfileдля уникнення каталогів у списку

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

Використання pathlibз 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

З list comprehension:

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

Крім того, використовувати pathlib.Path()замість цьогоpathlib.Path(".")

Використовуйте метод glob у pathlib.Path ()

import pathlib

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

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

Отримайте всі та лише файли з 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']

Отримуйте лише файли з наступним та переходьте до каталогу

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

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

Отримуйте лише каталоги з наступним і ходіть у каталог

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

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

Отримайте всі імена субдірера за допомогою 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() від Python 3.5 і більше

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

Приклади:

Вих. 1: Скільки файлів у підкаталогах?

У цьому прикладі ми шукаємо кількість файлів, що входять до всього каталогу та його підкаталогів.

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'

Приклад 2: Як скопіювати всі файли з каталогу в інший?

Сценарій для замовлення на вашому комп'ютері, знаходження всіх файлів типу (за замовчуванням: pptx) та копіювання їх у нову папку.

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

Вих. 3: Як отримати всі файли у файлі txt

Якщо ви хочете створити txt-файл із усіма назвами файлів:

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

Приклад: txt з усіма файлами жорсткого диска

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

Весь файл C: \ в одному текстовому файлі

Це коротша версія попереднього коду. Змініть папку, з якої почати пошук файлів, якщо вам потрібно почати з іншого місця. Цей код генерує 50 Мб текстового файлу на моєму комп’ютері, дещо менше 500 000 рядків з файлами з повним шляхом.

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

Як записати файл з усіма шляхами у папку типу

За допомогою цієї функції ви можете створити txt-файл, який буде мати ім'я типу файлу, який ви шукаєте (наприклад, pngfile.txt) з усім повним шляхом усіх файлів цього типу. Думаю, це може бути корисним часом.

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

(Нове) Знайдіть усі файли та відкрийте їх за допомогою графічного інтерфейсу tkinter

Я просто хотів додати в цьому 2019 році невеличку програму, щоб шукати всі файли в режимі і мати можливість їх відкрити, двічі клацнувши по імені файлу у списку. введіть тут опис зображення

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

13
Це сутіння занадто багато відповідей на не задані тут питання. Можливо, варто також пояснити, що таке застереження або рекомендовані підходи. Мені не краще знати один спосіб проти 20 способів зробити те саме, якщо я також не знаю, який є більш підходящим для використання, коли.
cs95

Гаразд, якнайшвидше я погляну на свою відповідь і спробую зробити її більш чистою та з кориснішою інформацією про різницю між методами тощо
Giovanni G. PY

Не слід визначати розширення файлу, перевіряючи, чи містить ім'я файлу підрядку. Це може спричинити багато неприємностей. Я рекомендую завжди перевіряти, чи закінчується ім'я файлу певним підрядком.
ni1ight

Добре, @ n1light я змінив код ...
Джованні Г. PY

811
import os
os.listdir("somedirectory")

поверне список усіх файлів і каталогів у "somedirectory".


11
Це повертає відносний шлях файлів порівняно з повним шляхом, поверненим доglob.glob
xji

22
@JIXiang: os.listdir()завжди повертає прості імена файлів (не відносні шляхи). Що glob.glob()повертається, визначається форматом шляху вхідного шаблону.
mklement0

os.listdir () -> Він завжди перераховує dir та файл у вказаному місці. Чи є спосіб перерахувати лише каталог, а не файли?
RonyA

160

Однорядне рішення для отримання лише списку файлів (без підкаталогів):

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

або абсолютні імена:

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

7
Лише однолінійний, якщо ви вже є import os. Здається менш лаконічним, ніж glob()для мене.
ArtOfWarfare

4
Проблема з глобалом полягає в тому, що папка під назвою 'something.something' буде повернена glob ('/ home / adam /*.*')
Ремі

6
В OS X є щось, що називається пакет. Це каталог, який, як правило, слід розглядати як файл (як .tar). Чи хочете ви, щоб вони трактувались як файл чи каталог? Використання glob()трактує це як файл. Ваш метод трактує це як каталог.
ArtOfWarfare

132

Отримання повних шляхів до файлу з каталогу та всіх його підкаталогів

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

  • Шлях, який я надав у вищевказаній функції, містив 3 файли - два з них у кореневій директорії, а інший у підпапці під назвою "SUBFOLDER". Тепер ви можете робити такі речі, як:
  • print full_file_paths який надрукує список:

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

Якщо ви хочете, ви можете відкривати та читати вміст або зосереджуватись лише на файлах із розширенням ".dat", як у коді нижче:

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

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


Це одна і єдина відповідь.
thelearner

78

Оскільки у версії 3.4 для цього є вбудовані ітератори, які є набагато ефективнішими, ніж os.listdir():

pathlib: Нове у версії 3.4.

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

Відповідно до PEP 428 , мета pathlibбібліотеки полягає у забезпеченні простої ієрархії класів для обробки шляхів файлової системи та загальних операцій, які користувачі виконують над ними.

os.scandir(): Нове у версії 3.5.

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

Зауважте, що він os.walk()використовує os.scandir()замість os.listdir()версії 3.5, а його швидкість зросла в 2-20 разів відповідно до PEP 471 .

Дозвольте також почитати коментар ShadowRanger нижче.


1
Дякую! Я думаю, що це єдине рішення, не повертаючись безпосередньо a list. Можна використовувати p.nameзамість першого, pякщо бажано.
jeromej

1
Ласкаво просимо! Я вважаю за краще створювати pathlib.Path()екземпляри, оскільки у них є багато корисних методів, я б не хотів витрачати відходи. Ви також можете зателефонувати str(p)на них для імен шляхів.
SzieberthAdam

6
Примітка: os.scandirрішення буде більш ефективним , ніж os.listdirз os.path.is_fileчеком або тощо, навіть якщо вам потрібно list(так що ви не виграють від ледачого ітерації), тому що os.scandirвикористовує ОС при умови API , які дають вам is_fileінформацію безкоштовно , як він перебирає , ні за файл туди і назад на диск до statних на всіх (на Windows, то DirEntryдобуде вам повна statінформацію безкоштовно, на * NIX систем він повинен statдля інформації позамежного is_file, is_dirі т.д., але DirEntryкешу на перше statдля зручності).
ShadowRanger

1
Ви також entry.nameможете отримати лише ім'я файлу або entry.pathотримати повний шлях. Більше не існує os.path.join ().
користувач136036

56

Попередні примітки

  • Хоча існує чітка диференціація між файлом і каталогом в тексті запитання термінами , деякі можуть стверджувати, що каталоги насправді є спеціальними файлами
  • Заява: " всі файли каталогу " можна інтерпретувати двома способами:
    1. Усі прямі (або 1 рівень) нащадки тільки
    2. Усі нащадки у цілому дереві каталогів (у тому числі в підкаталогах)
  • Коли питання було задано, я думаю, що Python 2 була версією LTS , однак зразки коду будуть виконуватись Python 3 ( .5 ) (я буду тримати їх як можливо суміснішими Python 2 ; також будь-який код, що належить Python, який я збираюся опублікувати, походить від v3.5.4 - якщо не вказано інше). Це має наслідки, пов’язані з іншим ключовим словом у питанні: " додати їх у список ":

    • У версіях pre Python 2.2 послідовності (ітерабелі) були здебільшого представлені списками (кортежі, набори, ...)
    • У Python 2.2 було введено поняття генератора ( [Python.Wiki]: Generators ) - люб’язно [Python 3]: твердження про вихід ). З плином часу почали з'являтися аналоги генераторів для функцій, які поверталися / працювали зі списками
    • У Python 3 генератор - це поведінка за замовчуванням
    • Не впевнений, що повернення списку все-таки є обов'язковим (або це зробить і генератор), але передача генератора в конструктор списку створить список із нього (а також споживатиме його). Наведений нижче приклад ілюструє відмінності на [Python 3]: map ( функція, ітерабельний, ... )
    >>> 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'>)
  • Приклади базуватимуться на каталозі root_dir із наступною структурою (цей приклад призначений для Win , але я також використовую те саме дерево на 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


Рішення

Програмні підходи:

  1. [Пітон 3]: ос. listdir ( path = '.' )

    Поверніть список, що містить імена записів у каталозі, заданому шляхом. Список складається у довільному порядку і не включає спеціальні записи '.'та '..'...


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

    Більш детальний приклад ( 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()

    Примітки :

    • Є дві реалізації:
      • Той, що використовує генератори (звичайно, тут здається марним, оскільки я негайно конвертую результат у список)
      • Класичний (назви функцій, що закінчуються _old )
    • Рекурсія використовується (для потрапляння у підкаталоги)
    • Для кожної реалізації є дві функції:
      • Той, що починається з підкреслення ( _ ): "приватний" (не повинен називатися безпосередньо) - це робить всю роботу
      • Загальнодоступний (обгортка над попередніми): він просто знімає початковий шлях (якщо потрібно) від повернених записів. Це некрасива реалізація, але це єдина ідея, з якою я міг прийти в цей момент
    • З точки зору продуктивності генератори, як правило, трохи швидші (враховуючи як створення, так і ітерацію) ), але я не перевіряв їх на рекурсивних функціях, а також я повторюю всередині функції над внутрішніми генераторами - не знаю, як продуктивність доброзичливим є те
    • Пограйте з аргументами, щоб отримати різні результати


    Вихід :

    (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. [Пітон 3]: ос. scandir ( path = '.' ) ( Python 3.5 +, резервний порт : [PyPI]: scandir )

    Повертає ітератор os.DirEntry об'єктів , відповідних записів в каталозі заданої траєкторії . Записи подаються в довільному порядку, а спеціальні записи '.'і '..'не включаються.

    Використання scandir () замість listdir () може значно підвищити продуктивність коду, який також потребує інформації про тип файлу чи атрибути файлів, оскільки об'єкти os.DirEntry розкривають цю інформацію, якщо операційна система надає її під час сканування каталогу. Усі методи os.DirEntry можуть виконувати системний виклик, але is_dir () та is_file () зазвичай вимагають лише системного виклику для символічних посилань; os.DirEntry.stat () завжди вимагає системного виклику в Unix, але вимагає лише одного для символічних посилань у 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

    Примітки :

    • Це схоже на os.listdir
    • Але він також гнучкіший (і пропонує більше функціональних можливостей), більше Python ic (а в деяких випадках і швидше)


  1. [Пітон 3]: ос. ходити ( зверху, згори = Правда, onerror = Немає, наступні посилання = Неправдиво )

    Створіть імена файлів у дереві каталогів, переходячи по дереву зверху вниз або знизу вгору. Для кожного каталогу в дереві каталогів з коренем в вершині ( в тому числі і зверху сам), він дає 3-кортеж ( 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', [], [])

    Примітки :

    • Під сценами він використовує os.scandir( os.listdirдля старих версій)
    • Він робить важкий підйом, повторюючись у вкладених папках


  1. [Пітон 3]: глоб. glob ( ім'я шляху, *, рекурсивний = False ) ( [Python 3]: glob. iglob ( ім'я шляху, *, рекурсивний = False ) )

    Поверніть можливо порожній список імен шляхів , що відповідають імені шляху , який повинен бути рядок із специфікацією шляху. ім'я контуру може бути абсолютним (подобається /usr/src/Python-1.5/Makefile) або відносним (подобається ../../Tools/*/*.gif), і може містити подстановочні символи в оболонці. Зламані символьні посилання включаються в результати (як і в оболонці).
    ...
    Змінено у версії 3.5 : Підтримка рекурсивних глобусів за допомогою " **".


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

    Примітки :

    • Використання os.listdir
    • Для великих дерев (особливо якщо ввімкнено рекурсивний характер) переважніший іглоб
    • Дозволяє розширену фільтрацію на основі імені (завдяки підстановці)


  1. [Python 3]: шлях до класу. Шлях ( * сегменти шляху ) ( Python 3.4 +, резервний порт : [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']

    Примітки :

    • Це один із способів досягнення нашої мети
    • Це стиль управління OOP
    • Пропонує безліч функціональних можливостей


  1. [Python 2]: dircache.listdir (шлях) ( лише для 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) через [Python 3]: ctypes - Бібліотека іноземних функцій для Python ( специфічна для POSIX )

    ctypes - це бібліотека іноземних функцій для Python. Він надає C-сумісні типи даних та дозволяє викликати функції в DLL або спільних бібліотеках. З його допомогою можна обернути ці бібліотеки в чистий Python.

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

    Примітки :

    • Він завантажує три функції від libc (завантажуються в поточному процесі) та викликає їх (для більш детальної перевірки [SO]: Як перевірити, чи існує файл без винятків? (@ Відповідь CristiFati) - останні примітки з пункту №4. ). Це ставило б такий підхід дуже близько до краю Python / C
    • LinuxDirent64 - це представлення ctypes struct dirent64 від [man7]: dirent.h (0P) (так це константи DT_ ) з моєї машини: Ubtu 16 x64 ( 4.10.0-40-generic та libc6-dev: amd64 ). Для інших ароматів / версій визначення структури може відрізнятися, і якщо так, псевдонім ctypes повинен бути оновлений, інакше це призведе до не визначеної поведінки
    • Він повертає дані у os.walkформаті. Я не намагався зробити його рекурсивним, але, виходячи з існуючого коду, це було б досить тривіальною задачею
    • Все також можливо на Win , дані (бібліотеки, функції, структури, константи, ...) відрізняються


    Вихід :

    [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 конкретно)

    Отримує список відповідних імен файлів за допомогою API Unicode Windows. Інтерфейс до API FindFirstFileW / FindNextFileW / Знайти функції закриття.


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

    Примітки :


  1. Встановіть якийсь (інший) сторонній пакет, який виконує трюк
    • Швидше за все, буде покладатися на одне (або більше) вищезазначеного (можливо, з невеликими налаштуваннями)


Примітки :

  • Код повинен бути переносним (за винятком місць, націлених на певну область - які позначені) або перехресними:

    • платформа ( Nix , Win ,)
    • Версія Python (2, 3,)
  • Для наведених вище варіантів використовувались декілька стилів шляху (абсолютні, родичі), щоб проілюструвати той факт, що використовувані "інструменти" є гнучкими в цьому напрямку

  • os.listdirі os.scandirвикористовувати opendir / readdir / closedir ( [MS.Docs]: функція FindFirstFileW / [MS.Docs]: функція FindNextFileW / [MS.Docs]: функція FindClose ) (через [GitHub]: python / cpython - (головний) cpython / Модулі / posixmodule.c )

  • win32file.FindFilesWтакож використовує ці ( Win конкретні) функції (через [GitHub]: mhammond / pywin32 - (master) pywin32 / win32 / src / win32file.i )

  • _get_dir_content (з пункту №1 ) можна реалізувати, використовуючи будь-який із цих підходів (для деяких знадобиться більше роботи, а деякі менше)

    • Можна виконати деяку розширену фільтрацію (замість просто файлу проти dir): наприклад, аргумент include_folders може бути замінений іншим (наприклад, filter_func ), який би був функцією, яка приймає шлях як аргумент: filter_func=lambda x: True(це не викреслює що завгодно) і всередині _get_dir_content щось на кшталт: if not filter_func(entry_with_path): continue(якщо функція не вдасться до одного запису, вона буде пропущена), але чим складніший код стає, тим довше буде потрібно для його виконання
  • Нота бене! Оскільки використовується рекурсія, я мушу зазначити, що я робив кілька тестів на своєму ноутбуці ( Win 10 x64 ), абсолютно не пов'язаних з цією проблемою, і коли рівень рекурсії досягав значень десь у діапазоні ( 990 .. 1000) ( рекурсійна ліміт - 1000 (за замовчуванням)), я отримав StackOverflow :). Якщо дерево каталогів перевищує це обмеження (я не фахівець з ФС , тому не знаю, чи це можливо), це може бути проблемою.
    Треба також зазначити, що я не намагався збільшити рекурсійний ліміт, оскільки не маю досвіду в цій галузі (наскільки я можу збільшити його, перш ніж також збільшити стек на ОСрівень), але теоретично завжди буде можливість виходу з ладу, якщо глибина dir більша за найвищий можливий рекурсійний ліміт (на цій машині)

  • Зразки коду призначені лише для демонстраційних цілей. Це означає, що я не враховував обробку помилок (я не думаю, що немає спроб / крім / else / нарешті блокувати), тому код не є надійним (причина: тримати його якомога простіше і коротше ). Для виробництва також слід додати помилки

Інші підходи:

  1. Використовуйте Python лише як обгортку

    • Все робиться за допомогою іншої технології
    • Ця технологія використовується від Python
    • Найвідоміший аромат, який я знаю, - це те, що я називаю підходом адміністратора системи :

      • Використовуйте Python (або будь-яку мову програмування з цього приводу) для виконання команд оболонки (і аналізує їх результати)
      • Деякі вважають це акуратним злом
      • Я вважаю це більше схожим на кульгаве вирішення ( gainarie ), оскільки дія per se виконується з оболонки ( cmd у цьому випадку), і, отже, не має нічого спільного з Python .
      • Фільтрування ( grep/ findstr) або форматування виводу може бути здійснено з обох сторін, але я не збираюся наполягати на цьому. Також я навмисно використовував os.systemзамість 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

    Взагалі цього підходу слід уникати, оскільки якщо якийсь формат виводу команд трохи відрізняється між версіями / ароматами ОС , слід також адаптувати код розбору; не кажучи вже про відмінності між локалями).


48

Мені дуже сподобалась відповідь adamk , пропонуючи використовувати її glob()з однойменного модуля. Це дозволяє вам узгоджувати візерунок із *s.

Але, як в коментарях зазначали інші люди, вони glob()можуть стикатися через непослідовні напрямки косої риски. Щоб допомогти у цьому, я пропоную вам використовувати функції join()та expanduser()функції в os.pathмодулі, а можливо, і getcwd()функцію в osмодулі.

Як приклад:

from glob import glob

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

Сказане вище - жахливо - шлях був жорстко закодований і він буде працювати коли-небудь лише в Windows між іменем диска і \s, який жорстко кодується в шлях.

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

Вищезазначене працює краще, але воно покладається на назву папки, Usersяка часто зустрічається в Windows і не так часто зустрічається на інших ОС. Він також покладається на те, що користувач має конкретне ім'я 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'))

Це чудово працює на всіх платформах.

Ще один чудовий приклад, який ідеально працює на платформах і робить щось трохи інше:

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

Сподіваємось, що ці приклади допоможуть вам побачити потужність кількох функцій, які ви можете знайти в стандартних модулях бібліотеки Python.


4
Додаткова глобальна забава: починаючи з Python 3.5, **працює поки ви встановили recursive = True. Дивіться документи тут: docs.python.org/3.5/library/glob.html#glob.glob
ArtOfWarfare

35
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 

23

Якщо ви шукаєте реалізацію знахідки Python , це рецепт, який я використовую досить часто:

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

Тому я зробив з нього пакет PyPI , а також є сховище GitHub . Я сподіваюся, що хтось вважає це потенційно корисним для цього коду.


14

Для отримання більших результатів можна використовувати listdir()метод osмодуля разом з генератором (генератор - це потужний ітератор, який зберігає свій стан, пам’ятаєте?). Наступний код чудово працює з обома версіями: Python 2 та Python 3.

Ось код:

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)

listdir()Метод повертає список записів для даного каталогу. Метод os.path.isfile()повертається, Trueякщо даний запис є файлом. І yieldоператор залишає функцію, але зберігає його поточний стан, і він повертає лише ім'я запису, виявленого як файл. Все вищесказане дозволяє перевести цикл на функцію генератора.


11

Повертаючи список абсолютних файлових шляхів, не повторюється в підкаталогах

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

2
Примітка: os.path.abspath(f)була б дещо дешевшою заміною os.path.join(os.getcwd(),f).
ShadowRanger

Я був би ще ефективнішим, якщо ви почали з цього cwd = os.path.abspath('.'), а потім використовувались cwdзамість нього '.'та в os.getcwd()усьому світі, щоб уникнути навантаження зайвих системних викликів.
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

Тут я використовую рекурсивну структуру.


Те саме можна досягти лише в одному рядку з pathlib:filter(Path.is_file, Path().rglob('*'))
Георгієм

9

Мудрий вчитель одного разу сказав мені:

Коли існує декілька встановлених способів зробити щось, жоден з них не підходить для всіх випадків.

Таким чином я додам рішення для підмножини проблеми: досить часто ми хочемо лише перевірити, чи відповідає файл початковою і кінцевою рядком, не потрапляючи в підкаталоги. Таким чином, ми хотіли б функцію, яка повертає список імен файлів, наприклад:

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

Якщо ви хочете спочатку оголосити дві функції, це можна зробити:

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

Це рішення можна легко узагальнити регулярними виразами (і ви можете додати patternаргумент, якщо ви не хочете, щоб ваші шаблони завжди дотримувалися початку та кінця імені файлу).


6

Використання генераторів

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

Ще один дуже читаний варіант для Python 3.4+ - це використання pathlib.Path.glob:

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

Простіше зробити більш конкретними, наприклад, шукати лише вихідні файли Python, які не є символічними посиланнями, також у всіх підкаталогах:

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

3

Ось моя загальна функція для цього. Він повертає список шляхів до файлів, а не назви файлів, оскільки я вважаю це кориснішим. У нього є кілька необов’язкових аргументів, які роблять його універсальним. Наприклад, я часто використовую його з аргументами типу pattern='*.txt'або 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

Я надам зразок одного вкладиша, де вихідний шлях та тип файлу можуть бути надані як вхідні дані. Код повертає список імен файлів із розширенням csv. Використовуйте . у випадку, якщо всі файли потрібно повернути. Це також рекурсивно сканує підкаталоги.

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

Змініть розширення файлів та вихідний шлях за потребою.


1
Якщо ви збираєтесь використовувати glob, то просто використовуйте glob('**/*.csv', recursive=True). Не потрібно поєднувати це з os.walk()рекурсом ( recursiveі **підтримується з Python 3.5).
Мартійн Пітерс

2

Для python2: pip встановити rglob

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

2

dircache "Застаріло з версії 2.6: Модуль dircache видалено в 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 "Застаріло з версії 2.6: Модуль dircache видалено в Python 3.0."
Даніель Рейс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.