我试图写一个简单的Python脚本,将复制索引。在所有子目录(少数例外)中将TPL转换为index.html。

我在获取子目录列表时陷入了困境。


import os
def get_immediate_subdirectories(a_dir):
    return [name for name in os.listdir(a_dir)
            if os.path.isdir(os.path.join(a_dir, name))]

操作系统。在这种情况下,走路是你的朋友。

直接从文档中:

Walk()通过自顶向下或自底向上遍历目录树来生成目录树中的文件名。对于根在目录顶部的树中的每个目录(包括top本身),它会生成一个3元组(dirpath、dirnames、filename)。


使用Twisted的FilePath模块:

from twisted.python.filepath import FilePath

def subdirs(pathObj):
    for subpath in pathObj.walk():
        if subpath.isdir():
            yield subpath

if __name__ == '__main__':
    for subdir in subdirs(FilePath(".")):
        print "Subdirectory:", subdir

由于一些评论者问使用Twisted的库有什么好处,我将在这里稍微超出最初的问题。


分支中有一些改进的文档解释了FilePath的优点;你可能会想读一下。

More specifically in this example: unlike the standard library version, this function can be implemented with no imports. The "subdirs" function is totally generic, in that it operates on nothing but its argument. In order to copy and move the files using the standard library, you need to depend on the "open" builtin, "listdir", perhaps "isdir" or "os.walk" or "shutil.copy". Maybe "os.path.join" too. Not to mention the fact that you need a string passed an argument to identify the actual file. Let's take a look at the full implementation which will copy each directory's "index.tpl" to "index.html":

def copyTemplates(topdir):
    for subdir in subdirs(topdir):
        tpl = subdir.child("index.tpl")
        if tpl.exists():
            tpl.copyTo(subdir.child("index.html"))

上面的“subdirs”函数可以作用于任何类filepath对象。这意味着,其中包括ZipPath对象。不幸的是,ZipPath现在是只读的,但是可以扩展到支持写入。

您还可以为测试目的传递自己的对象。为了测试操作系统。在这里建议使用path-using api时,您必须处理导入的名称和隐式依赖项,并通常执行黑魔法以使您的测试正常工作。使用FilePath,你可以这样做:

class MyFakePath:
    def child(self, name):
        "Return an appropriate child object"

    def walk(self):
        "Return an iterable of MyFakePath objects"

    def exists(self):
        "Return true or false, as appropriate to the test"

    def isdir(self):
        "Return true or false, as appropriate to the test"
...
subdirs(MyFakePath(...))

这里有一种方法:

import os
import shutil

def copy_over(path, from_name, to_name):
  for path, dirname, fnames in os.walk(path):
    for fname in fnames:
      if fname == from_name:
        shutil.copy(os.path.join(path, from_name), os.path.join(path, to_name))


copy_over('.', 'index.tpl', 'index.html')

我只是写了一些代码来移动vmware虚拟机,最终使用os。路径和shutil来完成子目录之间的文件复制。

def copy_client_files (file_src, file_dst):
    for file in os.listdir(file_src):
            print "Copying file: %s" % file
            shutil.copy(os.path.join(file_src, file), os.path.join(file_dst, file))

它不是特别优雅,但确实有用。


import os

获取目录下的(全路径)直接子目录:

def SubDirPath (d):
    return filter(os.path.isdir, [os.path.join(d,f) for f in os.listdir(d)])

获取最新(latest)子目录:

def LatestDirectory (d):
    return max(SubDirPath(d), key=os.path.getmtime)

为什么没有人提到glob?glob允许您使用unix风格的路径名展开,它是我的go to函数,几乎适用于需要查找多个路径名的所有内容。这很简单:

from glob import glob
paths = glob('*/')

请注意,glob将返回带有最后斜杠的目录(就像unix一样),而大多数基于路径的解决方案将省略最后的斜杠。


选中“获取当前目录中所有子目录的列表”。

下面是Python 3的版本:

import os

dir_list = next(os.walk('.'))[1]

print(dir_list)

这个方法很好地一次性完成了这一切。

from glob import glob
subd = [s.rstrip("/") for s in glob(parent_dir+"*/")]

def get_folders_in_directories_recursively(directory, index=0):
    folder_list = list()
    parent_directory = directory

    for path, subdirs, _ in os.walk(directory):
        if not index:
            for sdirs in subdirs:
                folder_path = "{}/{}".format(path, sdirs)
                folder_list.append(folder_path)
        elif path[len(parent_directory):].count('/') + 1 == index:
            for sdirs in subdirs:
                folder_path = "{}/{}".format(path, sdirs)
                folder_list.append(folder_path)

    return folder_list

下面的函数可以被调用为:

get_folders_in_directores_recurrecursive (directory, index=1) ->给出了第一层的文件夹列表

get_folders_in_directores_recurrecursive (directory) ->给出所有子文件夹


import glob
import os

def child_dirs(path):
     cd = os.getcwd()        # save the current working directory
     os.chdir(path)          # change directory 
     dirs = glob.glob("*/")  # get all the subdirectories
     os.chdir(cd)            # change directory to the script original location
     return dirs

child_dirs函数的作用是:获取一个目录的路径,并返回其中直接子目录的列表。

dir
 |
  -- dir_1
  -- dir_2

child_dirs('dir') -> ['dir_1', 'dir_2']

我必须提到path.py库,我经常使用它。

获取直接子目录变得如此简单:

my_dir.dirs ()

完整的工作示例是:

from path import Path

my_directory = Path("path/to/my/directory")

subdirs = my_directory.dirs()

注意:my_directory仍然可以作为字符串操作,因为Path是string的子类,但提供了一堆有用的方法来操作路径


import pathlib


def list_dir(dir):
    path = pathlib.Path(dir)
    dir = []
    try:
        for item in path.iterdir():
            if item.is_dir():
                dir.append(item)
        return dir
    except FileNotFoundError:
        print('Invalid directory')

我对各种函数做了一些速度测试,以返回当前所有子目录的完整路径。

tl;博士: 总是使用scandir:

List_subfolders_with_paths = [f.]f在os.scandir(Path)中的路径if f.is_dir()]

额外的好处:使用scandir,你也可以通过使用f.name而不是f.path来获取文件夹名称。

这个函数(以及下面所有其他函数)不会使用自然排序。这意味着结果将像这样排序:1,10,2。要获得自然排序(1,2,10),请查看https://stackoverflow.com/a/48030307/2441026


结果: scandir比walk快3倍,比listdir(带过滤器)快32倍,比Pathlib快35倍,比listdir快36倍,比glob快37倍(!)

Scandir:           0.977
Walk:              3.011
Listdir (filter): 31.288
Pathlib:          34.075
Listdir:          35.501
Glob:             36.277

用W7x64测试,Python 3.8.1。文件夹,包含440个子文件夹。 如果你想知道listdir是否可以通过不执行两次os.path.join()来加速,是的,但基本上不存在区别。

代码:

import os
import pathlib
import timeit
import glob

path = r"<example_path>"



def a():
    list_subfolders_with_paths = [f.path for f in os.scandir(path) if f.is_dir()]
    # print(len(list_subfolders_with_paths))


def b():
    list_subfolders_with_paths = [os.path.join(path, f) for f in os.listdir(path) if os.path.isdir(os.path.join(path, f))]
    # print(len(list_subfolders_with_paths))


def c():
    list_subfolders_with_paths = []
    for root, dirs, files in os.walk(path):
        for dir in dirs:
            list_subfolders_with_paths.append( os.path.join(root, dir) )
        break
    # print(len(list_subfolders_with_paths))


def d():
    list_subfolders_with_paths = glob.glob(path + '/*/')
    # print(len(list_subfolders_with_paths))


def e():
    list_subfolders_with_paths = list(filter(os.path.isdir, [os.path.join(path, f) for f in os.listdir(path)]))
    # print(len(list(list_subfolders_with_paths)))


def f():
    p = pathlib.Path(path)
    list_subfolders_with_paths = [x for x in p.iterdir() if x.is_dir()]
    # print(len(list_subfolders_with_paths))



print(f"Scandir:          {timeit.timeit(a, number=1000):.3f}")
print(f"Listdir:          {timeit.timeit(b, number=1000):.3f}")
print(f"Walk:             {timeit.timeit(c, number=1000):.3f}")
print(f"Glob:             {timeit.timeit(d, number=1000):.3f}")
print(f"Listdir (filter): {timeit.timeit(e, number=1000):.3f}")
print(f"Pathlib:          {timeit.timeit(f, number=1000):.3f}")

使用pathlib的一行代码:

list_subfolders_with_paths = [p for p in pathlib.Path(path).iterdir() if p.is_dir()]