python标准库pathlib

pathlib --- 面向对象的文件系统路径 — Python 3.9.17 文档 官网

讲的比较好的文章 python路径操作新标准:pathlib 模块 - 知乎

2|0简介

  • 该模块提供表示文件系统路径的类,其语义适用于不同的操作系统

2|1优点(对比os.path)

  • 老的路径操作函数管理比较混乱,有的是导入 os, 有的又是在 os.path 当中,而新的用法统一可以用 pathlib 管理。
  • 老用法在处理不同操作系统 win,mac 以及 linux 之间很吃力。换了操作系统常常要改代码,还经常需要进行一些额外操作。
  • 老用法主要是函数形式,返回的数据类型通常是字符串。但是路径和字符串并不等价,所以在使用 os 操作路径的时候常常还要引入其他类库协助操作。新用法是面向对象,处理起来更灵活方便。
  • pathlib 简化了很多操作,用起来更轻松

3|0详解

3|1获取文件路径

  • 语法

    Path(__file__) #__file__是当前文件的绝对路径

    Path(__file__).parent #所在目录

    Path(__file__).parent.parent #所在目录的父目录 Path(文件的相对路径) Path(__file__).resolve() #仍然可以得到绝对路径 Path(__file__).parent / 'filename' #目录拼接文件名 用/

  • 示例1

    from pathlib import Path

    print(Path.cwd()) #你当前py文件的所在目录,类似于pwd

    print(Path.home()) #你当前用户的家目录(windows比如C:\Users\用户名)

  • 示例2

    # demo_pathlib.py
    from pathlib import Path
    file_abs_path = Path(__file__)  
    print('对象类型是: ',type(file_abs_path))  #pathlib.WindowsPath
    print('当前文件的绝对路径:',file_abs_path)
    file_relative_path = Path('demo_pathlib.py')
    print('当前文件的相对路径:',file_relative_path)
    print('当前文件的绝对路径(另外一种写法):',file_relative_path.resolve())
    
    parent_dir  = Path(__file__).parent  #还可以继续.parent,相当于cd ..和cd ../..
    print('当前文件的父目录:',parent_dir)
    print('路径拼接用/(忽略操作系统差异): ',parent_dir / file_relative_path) #
  • 注意

    • 不管字符串使用的是正斜杠 / 还是反斜杠 \, 在 windows 系统里,得到的路径都是反斜杠\, pathlib 会根据操作系统智能处理

3|2获取路径组成部分

from pathlib import Path
saolei_apk = Path(r'd:\com.kejia.mine.apk')
print(saolei_apk.name)
属性说明
name文件名,包含后缀名,如果是目录则获取目录名
stem文件名,不包含后缀。
suffix后缀,比如 .txt.png
parent父级目录,相当于 cd ..
anchor锚,目录前面的部分 C:\ 或者 /
  • 多级目录

    from pathlib import Path
    saolei_apk = Path(r'D:\software\aDrive\locales\am.pak')
    for parent in saolei_apk.parents:
        print(parent)

    D:\software\aDrive\locales

    D:\software\aDrive

    D:\software

    D:\

    • 如果是os模块,要获取其父目录用的是os.path.dirname(),多级目录的话就麻烦,对比一下

      import os
      os_saolei_apk_dir  = os.path.dirname(r'D:\software\aDrive\locales\am.pak')
      print(os_saolei_apk_dir)
      os_saolei_apk_parent_dir = os.path.dirname(os.path.dirname(r'D:\software\aDrive\locales\am.pak'))
      print(os_saolei_apk_parent_dir)
      
      
      from pathlib import Path
      pathlib_saolei_apk = Path(r'D:\software\aDrive\locales\am.pak')
      print(pathlib_saolei_apk.parent)
      print(pathlib_saolei_apk.parent.parent)  #就相当于cd..多次
      print(pathlib_saolei_apk.parents[1])  #你还可以用parents,注意0是第一层所在目录,1是父目录,2是爷目录....

3|3获取文件属性

from pathlib import Path

saolei_apk = Path(r'd:\com.kejia.mine.apk')
print(saolei_apk.stat())
#os.stat_result(st_mode=33206, st_ino=562949953558668, st_dev=3393479561, st_nlink=1, st_uid=0, st_gid=0, st_size=698179, st_atime=1648601046, st_mtime=1631589296, st_ctime=1631952752)

mtime = saolei_apk.stat().st_mtime
print(arrow.get(mtime).format('YYYY-MM-DD HH:MM:SS'))  

属性说明
st_mode权限模式
st_inoinode number
st_devdevice
st_nlink硬链接数
st_uid所属用户的user id
st_gid所属用户的group id
st_size文件的大小,以位为单位
st_atime文件访问时间
st_mtime文件修改时间
st_ctime文件创建时间
  • 注意3个时间都是时间戳,要获取好看的时间就用arrow(详见我的另外一篇博文Python第三方库_arrow)来获取。

3|4文件(夹)操作

  • 慎用!推荐用shutil

  • 示例

    from pathlib import Path
    newfile = Path(r'D:\20220402.txt')
    if not newfile.exists():
        print('创建文件')
        newfile.touch(exist_ok=False)
    else:
        print('删除文件')
        newfile.unlink()

操作说明
exists()是否存在
is_dir()是否是文件
is_file()是否是目录
touch(mode=0o666, exist_ok=True)创建文件,默认权限666,如果exist_ok为True,文件存在不做任何事情,若为False,文件存在执行touch会报错FileExistsError
unlink()删除文件!危险操作!
rmdir()删除目录非常危险,并且没有提示,一定要谨慎操作。一次只删除一级目录,且当前目录必须为空
mkdir()创建目录
read_text()读文件内容,不再需要重复去打开文件和管理文件的关闭了,下同
read_bytes()读取bytes
write_text写入文本,注意是w 模式,如果之前已经有文件内容,将会被覆盖
write_bytes写入bytes
replace(文件新路径)移动文件
  • 重命名

    txt_path = Path('archive/demo.txt')
    new_file = txt_path.with_name('new.txt')
    txt_path.replace(new_file)
  • 改后缀

    txt_path = Path('archive/demo.txt')
    new_file = txt_path.with_suffix('.json')
    txt_path.replace(new_file)

4|0实例

4|1批量移动

  • 现在有这个目录

    E:\test (6.5KB) 
    +-- 1 (6.5KB) 
    | +-- 1.txt (0b) 
    | `-- 1.xls (6.5KB) 
    `-- 2 
        `-- 2.txt (0b)
    

  • 移动所有子目录下的.txt文件到E:\test这个根目录下

    from pathlib import Path
    def move_file_to(srcdir,dstdir,file_pattern):
        file = Path(srcdir).rglob(file_pattern)
        for _ in file:
            Path(_).replace(Path(dstdir) / Path(_).name)
    
    move_file_to(srcdir=r'e:\test',dstdir=r'e:\test',file_pattern='*.txt')

4|2批量修改后缀

  • 还是上面的目录结构

    E:\test (6.5KB) 
    +-- 1 (6.5KB) 
    | +-- 1.txt (0b) 
    | `-- 1.xls (6.5KB) 
    `-- 2 
        `-- 2.txt (0b)
    
    from pathlib import Path
    def change_suffix(dst_dir,old_suffix,new_suffix):
        file = Path(dst_dir).rglob('*.'+old_suffix)
        if list(file):
            for _ in file:
                new_ = Path(_).with_suffix('.'+new_suffix)
                Path(_).replace(new_)
        else:
            raise Exception(f'file-type:{old_suffix} not found(recursive) in {dst_dir}')
    change_suffix(dst_dir=r'e:\test',old_suffix='txt',new_suffix='docx')
  • 修改后

    $ tree
    E:\test (6.5KB)
    +-- 1 (6.5KB)
    |   +-- 1.docx (0b)
    |   `-- 1.xls (6.5KB)
    `-- 2
        `-- 2.docx (0b)
    
    • rglob是递归,glob只会找一个目录下
    • glob得到的是一个生成器,可以用list来转化成列表

4|3统计目录下的文件类型

  • 还是刚才的目录结构

    E:\test (6.5KB)
    +-- 1 (6.5KB)
    |   +-- 1.txt (0b)
    |   `-- 1.xls (6.5KB)
    `-- 2
        `-- 2.txt (0b)
  • 示例代码

    import collections
    from pathlib import Path
    path = Path(r'e:\test\1')
    files = [f.suffix for f in path.iterdir() if f.is_file()]
    print(dict(collections.Counter(files)))  #{'.txt': 1, '.xls': 1}
  • 但是上面的代码不能递归,就是当前目录下的文件的类型

  • 改造一下

    import collections
    from pathlib import Path
    path = Path(r'e:\test')
    files = [f.suffix for f in path.rglob('*.*') if f.is_file()]
    print(dict(collections.Counter(files)))

4|4统计某个目录下最近修改的文件

  • 转载知乎原文的代码

    from pathlib import Path
    path = Path.cwd()
    print(max(
        [(f.stat().st_mtime, f)
         for f in path.iterdir()
         if f.is_file()]
    ))
    • 也不能递归,你知道怎么改吗?
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值