ไดเร็กทอรีรายการ Python ไดเร็กทอรีย่อยและไฟล์


130

ฉันพยายามสร้างสคริปต์เพื่อแสดงรายการไดเร็กทอรีไดเร็กทอรีย่อยและไฟล์ทั้งหมดในไดเร็กทอรีที่กำหนด
ฉันลองสิ่งนี้:

import sys,os

root = "/home/patate/directory/"
path = os.path.join(root, "targetdirectory")

for r,d,f in os.walk(path):
    for file in f:
        print os.path.join(root,file)

โชคไม่ดีที่มันทำงานไม่ถูกต้อง
ฉันได้รับไฟล์ทั้งหมด แต่ไม่ใช่เส้นทางที่สมบูรณ์

ตัวอย่างเช่นถ้าโครงสร้าง dir จะเป็น:

/home/patate/directory/targetdirectory/123/456/789/file.txt

มันจะพิมพ์:

/home/patate/directory/targetdirectory/file.txt

สิ่งที่ฉันต้องการคือผลลัพธ์แรก ความช่วยเหลือใด ๆ ที่จะได้รับการชื่นชมอย่างมาก! ขอบคุณ

คำตอบ:


226

ใช้os.path.joinเพื่อเชื่อมไดเร็กทอรีและชื่อไฟล์เข้าด้วยกัน:

for path, subdirs, files in os.walk(root):
    for name in files:
        print os.path.join(path, name)

สังเกตการใช้pathและไม่ได้rootอยู่ในการเชื่อมต่อเนื่องจากการใช้งานrootจะไม่ถูกต้อง


ใน Python 3.4 มีการเพิ่มโมดูลpathlibเพื่อให้ปรับเปลี่ยนเส้นทางได้ง่ายขึ้น ดังนั้นสิ่งที่เทียบเท่าos.path.joinจะเป็น:

pathlib.PurePath(path, name)

ข้อดีpathlibคือคุณสามารถใช้วิธีการต่างๆที่เป็นประโยชน์บนเส้นทาง หากคุณใช้Pathตัวแปรที่เป็นรูปธรรมคุณยังสามารถเรียกใช้ระบบปฏิบัติการจริงผ่านพวกเขาได้เช่นการเปลี่ยนเป็นไดเรกทอรีการลบเส้นทางการเปิดไฟล์ที่ชี้ไปและอื่น ๆ อีกมากมาย


นี่เป็นคำตอบเดียวที่มีประโยชน์สำหรับคำถามมากมายที่ถูกถามเกี่ยวกับ "วิธีรับไฟล์ทั้งหมดซ้ำใน python"
harrisonfooord

รายการความเข้าใจ: all_files = [os.path.join (path, name) สำหรับชื่อในไฟล์สำหรับ path, subdirs, files ใน os.walk (โฟลเดอร์)]
Nir

ใน Python3 ใช้วงเล็บสำหรับฟังก์ชันการพิมพ์print(os.path.join(path, name))
Ehsan

45

ในกรณี ... รับไฟล์ทั้งหมดในไดเร็กทอรีและไดเร็กทอรีย่อยที่ตรงกับรูปแบบบางอย่าง (ตัวอย่างเช่น * .py):

import os
from fnmatch import fnmatch

root = '/some/directory'
pattern = "*.py"

for path, subdirs, files in os.walk(root):
    for name in files:
        if fnmatch(name, pattern):
            print os.path.join(path, name)

10

นี่คือซับเดียว:

import os

[val for sublist in [[os.path.join(i[0], j) for j in i[2]] for i in os.walk('./')] for val in sublist]
# Meta comment to ease selecting text

วงนอกสุดval for sublist in ...แบนรายการให้เป็นมิติเดียว jห่วงรวบรวมรายชื่อของทุก basename ไฟล์และร่วมไปยังเส้นทางปัจจุบัน ในที่สุดiลูปจะวนซ้ำในไดเรกทอรีและไดเรกทอรีย่อยทั้งหมด

ตัวอย่างนี้ใช้เส้นทางแบบฮาร์ดโค้ด./ในการos.walk(...)โทรคุณสามารถเสริมสตริงเส้นทางใดก็ได้ที่คุณต้องการ

หมายเหตุ: os.path.expanduserและ / หรือos.path.expandvarsสามารถใช้สำหรับสตริงเส้นทางเช่น~/

ขยายตัวอย่างนี้:

ง่ายต่อการเพิ่มในการทดสอบชื่อไฟล์และการทดสอบชื่อไดเรกทอรี

ตัวอย่างเช่นการทดสอบ*.jpgไฟล์:

... for j in i[2] if j.endswith('.jpg')] ...

นอกจากนี้ไม่รวม.gitไดเร็กทอรี:

... for i in os.walk('./') if '.git' not in i[0].split('/')]

มันใช้งานได้ แต่เพื่อแยก. git directoy คุณต้องตรวจสอบว่า '.git' ไม่อยู่ในเส้นทางหรือไม่
Roman Rdgz

อ๋อ ควรเป็นถ้า ".git" ไม่อยู่ใน i [0] .split ('/')]
Roman Rdgz

ฉันอยากจะแนะนำos.walkมากกว่าการหมุนวนแบบแมนนวลเครื่องปั่นไฟนั้นยอดเยี่ยมไปใช้มัน
ThorSummoner

9

ไม่สามารถแสดงความคิดเห็นจึงเขียนคำตอบที่นี่ นี่คือบรรทัดเดียวที่ชัดเจนที่สุดที่ฉันเคยเห็น:

import os
[os.path.join(path, name) for path, subdirs, files in os.walk(root) for name in files]

4

คุณสามารถดูตัวอย่างที่ฉันทำ ใช้ฟังก์ชัน os.path.walk ซึ่งเลิกใช้แล้วระวังใช้รายการเพื่อจัดเก็บ filepaths ทั้งหมด

root = "Your root directory"
ex = ".txt"
where_to = "Wherever you wanna write your file to"
def fileWalker(ext,dirname,names):
    '''
    checks files in names'''
    pat = "*" + ext[0]
    for f in names:
        if fnmatch.fnmatch(f,pat):
            ext[1].append(os.path.join(dirname,f))


def writeTo(fList):

    with open(where_to,"w") as f:
        for di_r in fList:
            f.write(di_r + "\n")






if __name__ == '__main__':
    li = []
    os.path.walk(root,fileWalker,[ex,li])

    writeTo(li)

4

หนึ่งซับที่ง่ายกว่าเล็กน้อย:

import os
from itertools import product, chain

chain.from_iterable([[os.sep.join(w) for w in product([i[0]], i[2])] for i in os.walk(dir)])

2

เนื่องจากทุกตัวอย่างที่นี่เป็นเพียงการใช้walk(กับjoin) ฉันจึงต้องการแสดงตัวอย่างที่ดีและเปรียบเทียบกับlistdir:

import os, time

def listFiles1(root): # listdir
    allFiles = []; walk = [root]
    while walk:
        folder = walk.pop(0)+"/"; items = os.listdir(folder) # items = folders + files
        for i in items: i=folder+i; (walk if os.path.isdir(i) else allFiles).append(i)
    return allFiles

def listFiles2(root): # listdir/join (takes ~1.4x as long) (and uses '\\' instead)
    allFiles = []; walk = [root]
    while walk:
        folder = walk.pop(0); items = os.listdir(folder) # items = folders + files
        for i in items: i=os.path.join(folder,i); (walk if os.path.isdir(i) else allFiles).append(i)
    return allFiles

def listFiles3(root): # walk (takes ~1.5x as long)
    allFiles = []
    for folder, folders, files in os.walk(root):
        for file in files: allFiles+=[folder.replace("\\","/")+"/"+file] # folder+"\\"+file still ~1.5x
    return allFiles

def listFiles4(root): # walk/join (takes ~1.6x as long) (and uses '\\' instead)
    allFiles = []
    for folder, folders, files in os.walk(root):
        for file in files: allFiles+=[os.path.join(folder,file)]
    return allFiles


for i in range(100): files = listFiles1("src") # warm up

start = time.time()
for i in range(100): files = listFiles1("src") # listdir
print("Time taken: %.2fs"%(time.time()-start)) # 0.28s

start = time.time()
for i in range(100): files = listFiles2("src") # listdir and join
print("Time taken: %.2fs"%(time.time()-start)) # 0.38s

start = time.time()
for i in range(100): files = listFiles3("src") # walk
print("Time taken: %.2fs"%(time.time()-start)) # 0.42s

start = time.time()
for i in range(100): files = listFiles4("src") # walk and join
print("Time taken: %.2fs"%(time.time()-start)) # 0.47s

อย่างที่คุณเห็นด้วยตัวคุณเองlistdirเวอร์ชันนี้มีประสิทธิภาพมากกว่ามาก (และjoinช้า)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.