如何在Python中列出文件或目录目标的所有文件与文件夹?
函数说明
我想要编写一个函数,接收文件系统中的路径目标target作为输入,它可以是目录,也可以是文件。
该函数需要返回target下所有子目标的文件和文件夹列表。
详细说明如下:
- 若
target是文件,返回值为包含该文件完全限定路径的长度为1的列表。 - 若
target是目录,返回值应包含该目录的递归子内容,包括目录本身。 - 返回项需按排序后的顺序排列
- 返回项需能区分是文件路径还是目录路径
Stack Overflow上的已有问题
Stack Overflow上有类似问题,但均未覆盖此场景。
以下是简要总结:
- 如何列出目录的所有文件?
- 获取当前目录的所有子目录列表
这两个问题的答案均假设目标是目录,无法处理目标为文件的情况。此外,第一个问题仅返回文件,不包含目录;第二个问题仅返回目录,不包含文件。
实现策略
该函数应拆分为三个步骤:
- 第一步:获取相对路径
- 第二步:通过映射操作将相对路径转换为绝对(完全限定)路径
- 第三步:对返回项进行排序
这种设计具备高度灵活性,每个函数仅负责一项任务且可组合,属于优秀的软件设计,即所谓的简洁设计。
另一种更优的设计可能是将文件和目录的收集拆分为两个独立函数,但这会导致目标被遍历两次,降低性能。
基础函数选择
我了解到有几种基础函数可选:
os.listdiros.scandiros.walkos.fwalk- 或许还有其他?
我不确定哪种是最佳选择。
尝试的解决方案
我已开始尝试实现,但因输入的目标路径可能是文件或目录,初始状态未知,实现起来相当复杂。这意味着接口层的逻辑需要与递归调用的逻辑不同。
我未能找到简单优雅的解决方案,因此认为肯定存在更合适的方法,只是我尚未发现。
基于以下示例:
import os def fast_scandir(target_dir: str) -> list[str]: items = [] for f in os.scandir(target_dir): if f.is_dir(): items.extend(fast_scandir(f.path)) if f.is_file(): items.append(f.path) items.sort() return items
该示例是一个简单的解决方案,但未满足所有需求,我据此写出了以下代码:
# 接口层,接收`target`,未知其为文件或目录 def fast_scandir_3(target:str) -> list[tuple[str, str]]: items:list[tuple[str, str]] = [] if os.path.isfile(target): item = ('f', target) items.extend(_fast_scandir_3_impl(item)) elif os.path.isdir(target): item = ('d', target) items.extend(_fast_scandir_3_impl(item)) return items
以下(实现层)代码非常糟糕,过于复杂,难以阅读和理解,肯定存在更直接的实现方式:
# 实现层 # TODO:后续将添加`sorted`排序和完全限定路径支持 def _fast_scandir_3_impl(target:tuple[str, str]) -> list[tuple[str, str]]: items:list[tuple[str, str]] = [] items.append(target) if target[0] == 'f': pass elif target[0] == 'd': target_path = target[1] for subtarget in os.listdir(target_path): if os.path.isfile(subtarget): target = ('f', subtarget) items.extend(_fast_scandir_3_impl(target)) elif os.path.isdir(subtarget): target = ('d', subtarget): items.extend(_fast_scandir_3_impl(target )) return items
实现完全限定路径的思路:
def _fast_scandir_3_fully_qualified_impl(target:tuple[str, str]) -> list[tuple[str, str]]: return ( list( map( lambda item: (item[0], os.path.abspath(item[1])), _fast_scandir_3_impl(target), ) ) )
实现排序的思路:
def _fast_scandir_3_fully_qualified_sorted_impl(target:tuple[str, str]) -> list[tuple[str, str]]: return sorted(_fast_scandir_3_fully_qualified_impl(target), key=lambda pair: pair[1])
最严重的问题是该实现并未完成预期功能。
此外,还有一些疑问:
- 使用
listdir实现是否正确? - 使用
sorted对返回项排序是否是最高效的方式?(上述实现中未展示)
内容的提问来源于stack exchange,提问作者user2138149
相关产品推荐
相关产品推荐

