Python面试题系列之05 遍历目录并筛选指定文件

Python面试题系列之05: 设计实现遍历目录及子目录,并抓取.txt文件?

Question

设计实现遍历目录及子目录,并抓取.txt文件?

知识点详解

这道题并不难,这里我们用三种思路来实现这个小需求。依次会用到os模块、glob模块、pathlib模块。

方法一:利用os模块

python的os库有很多和文件,路径,执行系统命令相关的功能。比如我们可以使用os.listdir()方法来列出目录下的所有文件和目录放入一个列表进行返回,但是listdir()函数不可对目录的子目录进行扫描。

很多时候我们需要将某个文件夹下的所有文件都要找出来,那么此时我们就需要os.walk()。它通过在目录树中向下或向上游走,输出目录的文件名。

os.walk()方法的语法格式如下:

os.walk(top[, topdown=True[, onerror=None[, followlinks=False]]])
  • top – 是你所要遍历的目录的地址
  • topdown –可选,为 True,则优先遍历 top 目录,否则优先遍历 top 的子目录。
  • onerror – 可选,需要一个 callable 对象,当 walk 需要异常时,会调用。
  • followlinks – 可选,若为 True,则会遍历目录下的快捷方式。

该函数没有返回值,会使用yield关键字抛出一个存放当前该层目录(dirpath, dirnames, filenames)的三元组,最终将所有目录层的的结果变为一个生成器。

  • dirpath是一个string,代表目录的路径;
  • dirnames是一个list,包含了dirpath下所有子目录的名字;
  • filenames是一个list,包含了非目录文件的名字。这些名字不包含路径信息,如果需要得到全路径,需要使用 os.path.join(dirpath, filename);

了解了os.walk的语法后,接下来直接上代码,来实现这个需求。

import os

def get_files(dir, suffix):
    res = []
    for dirpath,dirnames,filenames in os.walk(dir):
        for filename in filenames:
            name, suf = os.path.splitext(filename)
            if suf == suffix:
                res.append(os.path.join(dirpath, filename))

    print(res)

get_files("E:\Pythonista", '.txt')

方法二:利用glob模块

glob模块可以使用Unix shell风格的通配符匹配符合特定格式的文件和文件夹,跟windows的文件搜索功能差不多。glob模块并非调用一个子shell实现搜索功能,而是在内部调用了os.listdir()fnmatch.fnmatch()

glob模块支持的通配符如下:

  • * 匹配0或多个字符
  • ** 匹配所有文件、目录、子目录和子目录里的文件(Python 3.5版本新增)
  • ? 匹配1个字符,与正则表达式里的?不同
  • [exp] 匹配指定范围内的字符,如:[1-9]匹配1至9范围内的字符
  • [!exp] 匹配不在指定范围内的字符

接下来就利用glob模块来实现这个需求,以下是具体代码:

from glob import iglob

def func(filepath, suffix):
    for i in iglob(f"{filepath}/**/*{suffix}", recursive=True):
        print(i)

if __name__ == "__main__":
    suffix = ".txt"
    func("E:\Pythonista", suffix)

自从Python 3.5版本新增了**通配符,glob模块变得更加易用,真是太赞了😉

方法三:利用pathlib模块

pathlib模块是Python 3.4版本中新增的模块,pathlib绝不仅仅是替换了os.path那么简单,它可以说是路径处理的瑞士军刀。它完全采用面向对象的编程方式,尤其是在处理配置路径方面简直太方便了。

闲话少说,我们直接用Path().rglob来递归遍历指定的文件。

from pathlib import Path

src = "E:\Pythonista"
for item in Path(src).rglob('*.txt'):
    print(item)

简单几行代码,轻松搞定😎

Answer

无论用os模块、还是glob模块、或是pathlib模块均可实现这一需求,详细代码见上文内容。

后记

上述三种方法都能实现这一需求,但哪种方法更加简便已不言而喻。所以还是希望大家能多了解一些Python新版本的特性,紧跟技术前沿😁😁😁

可通过如下这个链接来了解Python 3中每个版本加入的新特性。

https://docs.python.org/3.x/whatsnew/3.x.html

注:需要把x替换成实际版本号即可。好了,以上就是本篇全部内容。

备注:本篇首发于知识星球「人人都是Pythonista」。


文章作者: &娴敲棋子&
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 &娴敲棋子& !
评论
  目录