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

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

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


当前回答

下面是一行代码:

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…循环将列表平展为一维。j循环收集每个文件basename的列表,并将其连接到当前路径。最后,i循环遍历所有目录和子目录。

这个例子在os.walk(…)调用中使用了硬编码的路径。/,你可以补充任何你喜欢的路径字符串。

注意:os.path.expanduser和/或os.path.expandvars可以用于~/这样的路径字符串

扩展这个例子:

很容易在文件basename测试和directoryname测试中添加。

例如,测试*.jpg文件:

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

此外,不包括.git目录:

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

其他回答

你可以看看我做的这个样品。它使用os.path.walk函数,该函数已被弃用。使用列表存储所有文件路径

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)

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

使用任何受支持的Python版本(3.4+),都应该使用pathlib。Rglob来递归地列出当前目录和所有子目录的内容:

from pathlib import Path


def generate_all_files(root: Path, only_files: bool = True):
    for p in root.rglob("*"):
        if only_files and not p.is_file():
            continue
        yield p


for p in generate_all_files(Path("."), only_files=False):
    print(p)

如果你想要复制粘贴的东西:

例子

文件夹结构:

$ tree . -a
.
├── a.txt
├── bar
├── b.py
├── collect.py
├── empty
├── foo
│   └── bar.bz.gz2
├── .hidden
│   └── secrect-file
└── martin
    └── thoma
        └── cv.pdf

给:

$ python collect.py 
bar
empty
.hidden
collect.py
a.txt
b.py
martin
foo
.hidden/secrect-file
martin/thoma
martin/thoma/cv.pdf
foo/bar.bz.gz2

无法评论,所以在这里写下答案。这是我见过的最清晰的一句话:

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

下面是一行代码:

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…循环将列表平展为一维。j循环收集每个文件basename的列表,并将其连接到当前路径。最后,i循环遍历所有目录和子目录。

这个例子在os.walk(…)调用中使用了硬编码的路径。/,你可以补充任何你喜欢的路径字符串。

注意:os.path.expanduser和/或os.path.expandvars可以用于~/这样的路径字符串

扩展这个例子:

很容易在文件basename测试和directoryname测试中添加。

例如,测试*.jpg文件:

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

此外,不包括.git目录:

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