我试图使一个脚本列出所有目录,子目录,和文件在一个给定的目录。 我试了一下:

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

我需要的是第一个结果。任何帮助都将不胜感激!谢谢。


当前回答

使用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变量,你也可以通过它们进行实际的OS调用,比如改变到一个目录,删除路径,打开它指向的文件等等。

其他回答

使用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变量,你也可以通过它们进行实际的OS调用,比如改变到一个目录,删除路径,打开它指向的文件等等。

因为这里的每个例子都只是使用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版本效率更高。(这个连接很慢)

另一种选择是使用标准库中的glob模块:

import glob

path = "/home/patate/directory/targetdirectory/**"

for path in glob.glob(path, recursive=True):
    print(path)

如果你需要一个迭代器,你可以使用iglob作为替代:

for file in glob.iglob(my_path, recursive=True):
    # ...

以防万一……获取目录中的所有文件和匹配某些模式的子目录(例如*.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))

简单一点的一行代码:

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