Python操作路径, pathlib 模块, pathlib替代os.path, pathlib模块用法详解, Python pathlib 教程

pathlib 库从 python3.4 开始,到 python3.6 已经比较成熟。如果你的新项目可以直接用 3.6 以上,建议用 pathlib。相比于老式的 os.path 有几个优势:

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

举个例子, 把所有的 txt 文本全部移动到 archive 目录当中(archive 目录必须存在)。

Python操作路径, pathlib 模块, pathlib替代os.path, pathlib模块用法详解, Python pathlib 教程
Python操作路径, pathlib 模块, pathlib替代os.path, pathlib模块用法详解, Python pathlib 教程

使用原来的用法:

import glob
import os
import shutil

# 获取运行目录下所有的 txt 文件。注意:不是这个文件目录下
print(glob.glob('*.txt'))

for file_name in glob.glob('*.txt'):
    new_path = os.path.join('archive', file_name)
    shutil.move(file_name, new_path)

 

新的写法:

from pathlib import Path

Path("demo.txt").replace('archive/demo.txt')

 

下面这张图,完美诠释pathlib的核心

Python操作路径, pathlib 模块, pathlib替代os.path, pathlib模块用法详解, Python pathlib 教程
Python操作路径, pathlib 模块, pathlib替代os.path, pathlib模块用法详解, Python pathlib 教程

 

安装

pip install pathlib

 

官网:https://pathlib.readthedocs.io/en/pep428/

 

常用属性和基本方法

Path
│
├── Attributes
│       ├── parts
│       ├── parent & parents
│       ├── name
│       ├── suffix & suffixes
│       └── stem
│
│
└── Methods
        ├── joinpath(*other)
        ├── cwd()
        ├── home()
        ├── exists()
        ├── expanduser()
        ├── glob()
        ├── rglob(pattern)
        ├── is_dir()
        ├── is_file()
        ├── is_absolute()
        ├── iterdir()
        ├── mkdir(mode=0o777, parents=False, exist_ok=False)
        ├── open(mode='r', buffering=-1, encoding=None, errors=None, newline=None)
        ├── rename(target)
        ├── replace(target)
        ├── resolve(strict=False)
        └── rmdir()

 

Path.parents  # 返回所有上级目录的列表

Path.parts  # 分割路径 类似os.path.split(), 不过返回元组

Path.suffix   # 返回文件后缀

Path.is_dir()  # 判断是否是目录

Path.is_file()  # 是否是文件

Path.exists()  # 判断路径是否存在

Path.open()  # 打开文件(支持with)

Path.resolve()  # 返回绝对路径

Path.cwd()  # 返回当前目录

Path.iterdir()  # 遍历目录的子目录或者文件

Path.mkdir()  # 创建目录

Path.rename()  # 重命名路径

Path.unlink()  # 删除文件或目录(目录非空触发异常)

Path.joinpath()  # 拼接路径

 

pathlib模块下Path类的基本使用

 

1. 路径组成部分

from pathlib import Path

path = r'D:\python\pycharm2020\program\pathlib模块的基本使用.py'
p = Path(path)
print(p.name)       # 获取文件名
print(p.stem)       # 获取文件名除后缀的部分
print(p.suffix)     # 获取文件后缀
print(p.parent)     # 相当于dirname
print(p.parent.parent.parent)
print(p.parents)    # 返回一个iterable 包含所有父目录
for i in p.parents:
    print(i)
print(p.parts)      # 将路径通过分隔符分割成一个元组

 

运行结果如下:

pathlib模块的基本使用.py
pathlib模块的基本使用
.py
D:\python\pycharm2020\program
D:\python
<WindowsPath.parents>
D:\python\pycharm2020\program
D:\python\pycharm2020
D:\python
D:\
('D:\\', 'python', 'pycharm2020', 'program', 'pathlib模块的基本使用.py')

 

2. 路径获取

  • Path.cwd():返回代表当前目录的新路径对象
  • Path.home():返回代表用户HOME目录的新路径对象
  • Path.resolve():返回获取路径的绝对路径
  • Path.expanduser():返回带有扩展的 ~ 和 ~user 结构的新路径

 

from pathlib import Path

path_1 = Path.cwd()       # 获取当前文件路径
path_2 = Path.home()
p1 = Path('~/pathlib模块的基本使用.py')
print(path_1)
print(path_2)
print(p1.expanduser())

 

运行结果如下:

D:\python\pycharm2020\program
C:\Users\Administrator
C:\Users\Administrator\pathlib模块的基本使用.py

 

3. 获取文件属性

Path.stat():返回一个包含该路径信息的os.stat_result对象

 

from pathlib import Path
import datetime

p = Path('pathlib模块的基本使用.py')
print(p.stat())            # 获取文件详细信息
print(p.stat().st_size)    # 文件的字节大小
print(p.stat().st_ctime)   # 文件创建时间
print(p.stat().st_mtime)   # 上次修改文件的时间
creat_time = datetime.datetime.fromtimestamp(p.stat().st_ctime)
st_mtime = datetime.datetime.fromtimestamp(p.stat().st_mtime)
print(f'该文件创建时间:{creat_time}')
print(f'上次修改该文件的时间:{st_mtime}')

 

运行结果如下:

os.stat_result(st_mode=33206, st_ino=3659174698076635, st_dev=3730828260, st_nlink=1, st_uid=0, st_gid=0, st_size=543, st_atime=1597366826, st_mtime=1597366826, st_ctime=1597320585)
543
1597320585.7657475
1597366826.9711637
该文件创建时间:2020-08-13 20:09:45.765748
上次修改该文件的时间:2020-08-14 09:00:26.971164

从返回.stat.st_属性不同的秒数(自 1970 年 1 月 1 日)的数字,可以用 time.fromtimestamp 将日期转换为有用的时间格式。

 

4. 绝对路径和判断文件夹是否存在

  • Path.exists():路径是否指向已存在的文件或目录
  • Path.resolve(strict=False):使路径成为绝对路径,解析任何符号链接。返回一个新的路径对象

 

from pathlib import Path

p1 = Path('pathlib模块的基本使用.py')          # 文件
p2 = Path(r'D:\python\pycharm2020\program')   # 文件夹 
absolute_path = p1.resolve()
print(absolute_path)
print(Path('.').exists())
print(p1.exists(), p2.exists())
print(p1.is_file(), p2.is_file())
print(p1.is_dir(), p2.is_dir())
print(Path('/python').exists())
print(Path('non_existent_file').exists())

 

运行结果如下:

D:\python\pycharm2020\program\pathlib模块的基本使用.py
True
True True
True False
False True
True

 

5. 子路径扫描

  • Path.iterdir():当path指向一个目录时,yield目录内容的路径对象

 

from pathlib import Path

p = Path('/python')
for child in p.iterdir():
    print(child)

 

运行结果如下:

\python\Anaconda
\python\EVCapture
\python\Evernote_6.21.3.2048.exe
\python\Notepad++
\python\pycharm-community-2020.1.3.exe
\python\pycharm2020
\python\pyecharts-assets-master
\python\pyecharts-gallery-master
\python\Sublime text 3

 

>>> cwd = Path.cwd()
>>> [path for path in cwd.iterdir() if cwd.is_dir()]
[
    WindowsPath('C:/Users/me/study/archive'), 
    WindowsPath('C:/Users/me/study/demo_01.py'), 
    WindowsPath('C:/Users/me/study/new_archive')
]

 

使用 iterdir() 可以统计目录下的不同文件类型:

>>> path = Path.cwd()
>>> files = [f.suffix for f in path.iterdir() if f.is_file()]
>>> collections.Counter(files)
Counter({'.py': 3, '.txt': 1})

 

查找目录下的指定文件 glob 。

使用模式匹配(正则表达式)匹配指定的路径。glob 只会匹配当前目录下, rglob 会递归所有子目录。下面这个例子,demo.txt 在 archive 子目录下。所以用 glob 找到的是空列表,rglob 可以找到。glob 得到的是一个生成器,可以通过 list() 转化成列表。

>>> cwd = Path.cwd()
>>> list(cwd.glob('*.txt'))
[]
>>> list(cwd.rglob('*.txt'))
[WindowsPath('C:/Users/me/study/archive/demo.txt')]

 

检查路径是否符合规则 match

>>> file = Path('/archive/demo.txt')
>>> file.match('*.txt')
True

 

  • Path.glob(pattern):将给定的相对模式在该路径所代表的目录中进行glob,产生所有匹配的文件(任何类型),“**”模式表示“该目录及其所有子目录,递归”。换句话说,它启用了递归通配符。
  • 注意:在大型目录树中使用“**”模式可能会消耗过多的时间

所有的文件该归于目录,返回一个生成器。

 

获取该文件目录下所有.py文件

from pathlib import Path

path = r'D:\python\pycharm2020\program'
p = Path(path)
file_name = p.glob('**/*.py')
print(type(file_name))   # <class 'generator'>
for i in file_name:
    print(i)

 

获取该文件目录下所有.jpg图片

from pathlib import Path

path = r'D:\python\pycharm2020\program'
p = Path(path)
file_name = p.glob('**/*.jpg')
print(type(file_name))   # <class 'generator'>
for i in file_name:
    print(i)

 

获取给定目录下所有.txt文件、.jpg图片和.py文件

from pathlib import Path

def get_files(patterns, path):
    all_files = []
    p = Path(path)
    for item in patterns:
        file_name = p.rglob(f'**/*{item}')
        all_files.extend(file_name)
    return all_files

path = input('>>>请输入文件路径:')
results = get_files(['.txt', '.jpg', '.py'], path)
print(results)
for file in results:
    print(file)

 

6. 路径拼接

pathlib 支持用 / 拼接路径。熟悉魔术方法的同学应该很容易理解其中的原理。

>>> Path.home() / 'dir' / 'file.txt'
C:\Users\me\dir\file.txt

 

如果用不惯 / ,也可以用类似 os.path.join 的方法:

>>> Path.home().joinpath('dir', 'file.txt')
C:\Users\me\dir\file.txt

 

7. 文件操作

创建文件 touch

>>> file = Path('hello.txt')
>>> file.touch(exist_ok=True)
None

>>> file.touch(exist_ok=False)
FileExistsError: [Errno 17] File exists: 'hello.txt'

exist_ok 表示当文件已经存在时,程序的反应。如果为 True,文件存在时,不进行任何操作。如果为 False, 则会报 FileExistsError 错误

 

创建目录 path.mkdir

用 os 创建目录分为 2 个函数 : mkdir() 和 makedirs()。 mkdir() 一次只能创建一级目录, makedirs() 可以同时创建多级目录:

>>> os.mkdir('dir/subdir/3dir')
FileNotFoundError: [WinError 3] 系统找不到指定的路径。: 'dir/subdir/3dir'

>>> os.makedirs('dir/subdir/3dir')
None

 

使用 pathlib 只需要用 path.mkdir() 函数就可以。它提供了 parents 参数,设置为 True 可以创建多级目录;不设置则只能创建 一层:

>>> path = Path('/dir/subdir/3dir')
>>> path.mkdir()
FileNotFoundError: [WinError 3] 系统找不到指定的路径。: 'dir/subdir/3dir'

>>> path.mkdir(parents=True)
None

 

Path.mkdir(mode=511,parents=False,exist_ok=False)

  • 在这个给定的路径上创建一个新目录。如果给定了模式,则将其与进程的 umask 值结合以确定文件模式和访问标志。如果路径已存在,则引发 FileExistsError。
  • 如果 parents 为真,则根据需要创建此路径的任何缺少的 parent;它们是使用默认权限创建的,不考虑模式(模仿 POSIX mkdir -p 命令)。
  • 如果 parents 为 false(默认值),则缺少的 parent 会引发 FileNotFoundError。
  • 如果 exists_ok 为 false(默认值),如果目标目录已存在,则会引发 FileExistsError。
  • 如果exist_ok 为True,FileExistsError 异常将被忽略(与 POSIX mkdir -p 命令的行为相同),但前提是最后一个路径组件不是现有的非目录文件。

在 3.5 版更改: 添加了 exists_ok 参数。

 

删除目录 path.rmdir()

Path.rmdir():删除该目录。删除目录非常危险,并且没有提示,一定要谨慎操作。一次只删除一级目录,且当前目录必须为空。

from pathlib import Path

p = Path(r'D:\python\pycharm2020\program\test')
p.mkdir()
p.rmdir()
from pathlib import Path

p = Path(r'D:\python\test1\test2\test3')
p.mkdir(parents=True)  # If parents is true, any missing parents of this path are created as needed
p.rmdir()    # 删除的是test3文件夹
from pathlib import Path

p = Path(r'D:\python\test1\test2\test3')
p.mkdir(exist_ok=True)

 

删除文件 path.unlink, 危险操作。

  • Path.unlink(missing_ok=False):删除此文件或符号链接。如果路径指向目录,请改用 Path.rmdir()。如果 missing_ok 为 false(默认值),则在路径不存在时引发 FileNotFoundError。如果 missing_ok 为真,FileNotFoundError 异常将被忽略。3.8 版更改:增加了missing_ok 参数。
  • Path.rename(target):将此文件或目录重命名为给定的目标,并返回一个指向目标的新Path实例。在 Unix 上,如果 target 存在并且是一个文件,如果用户有权限,它将被静默替换。target 可以是字符串或另一个路径对象。
  • Path.open(mode=’r’, buffering=-1, encoding=None, errors=None, newline=None):打开路径指向的文件,就像内置的open()函数一样。

 

from pathlib import Path

p = Path('foo.txt')
p.open(mode='w').write('some text')
target = Path('new_foo.txt')
p.rename(target)
content = target.open(mode='r').read()
print(content)
target.unlink()

 

pathlib 对读取和写入进行了简单的封装,不再需要重复去打开文件和管理文件的关闭了。

  • .read_text() 读取文本
  • .read_bytes() 读取 bytes
  • .write_text() 写入文本
  • .write_bytes() 写入 tytes
>>> file_path = Path('archive/demo.txt')

>>> file_path.read_text()   # 读取文本
'text in the demo.txt'

>>> file_path.read_bytes()  # 读取 bytes
b'text in the demo.txt'

>>> file.write_text('new words')  # 写入文本
9

>>> file.write_bytes(b'new words') # 写入 bytes
9

 

注意
file.write 操作使用的是 w 模式,如果之前已经有文件内容,将会被覆盖。

 

移动文件
txt_path = Path('archive/demo.txt')
res = txt_path.replace('new_demo.txt')
print(res)

这个操作会把 archive 目录下的 demo.txt 文件移动到当前工作目录,并重命名为 new_demo.txt。

移动操作支持的功能很受限。比如当前工作目录如果已经有一个 new_demo.txt 的文件,则里面的内容都会被覆盖。还有,如果需要移动到其他目录下,则该目录必须要存在,否则会报错:

# new_archive 目录必须存在,否则会报错
txt_path = Path('archive/demo.txt')
res = txt_path.replace('new_archive/new_demo.txt')
print(res)

 

为了避免出现同名文件里的内容被覆盖,通常需要进行额外处理。比如判断同名文件不能存在,但是父级目录必须存在;或者判断父级目录不存在时,创建该目录。

dest = Path('new_demo.txt')
if (not dest.exists()) and dest.parent.exists():
 txt_path.replace(dest)

 

重命名文件

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)

 

注意
不管是移动文件还是删除文件,都不会给任何提示。所以在进行此类操作的时候要特别小心。
对文件进行操作最好还是用 shutil 模块。

 

os and os.path VS pathlib

pathlib 可替代 os 和 os.path 的常用功能:

Python os.path() 模块

os.path 模块主要用于获取文件的属性。

 

以下是 os.path 模块的几种常用方法:

方法 说明
os.path.abspath(path) 返回绝对路径
os.path.basename(path) 返回文件名
os.path.commonprefix(list) 返回list(多个路径)中,所有path共有的最长的路径
os.path.dirname(path) 返回文件路径
os.path.exists(path) 如果路径 path 存在,返回 True;如果路径 path 不存在,返回 False。
os.path.lexists 路径存在则返回True,路径损坏也返回True
os.path.expanduser(path) 把path中包含的”~”和”~user”转换成用户目录
os.path.expandvars(path) 根据环境变量的值替换path中包含的”$name”和”${name}”
os.path.getatime(path) 返回最近访问时间(浮点型秒数)
os.path.getmtime(path) 返回最近文件修改时间
os.path.getctime(path) 返回文件 path 创建时间
os.path.getsize(path) 返回文件大小,如果文件不存在就返回错误
os.path.isabs(path) 判断是否为绝对路径
os.path.isfile(path) 判断路径是否为文件
os.path.isdir(path) 判断路径是否为目录
os.path.islink(path) 判断路径是否为链接
os.path.ismount(path) 判断路径是否为挂载点
os.path.join(path1[, path2[, …]]) 把目录和文件名合成一个路径
os.path.normcase(path) 转换path的大小写和斜杠
os.path.normpath(path) 规范path字符串形式
os.path.realpath(path) 返回path的真实路径
os.path.relpath(path[, start]) 从start开始计算相对路径
os.path.samefile(path1, path2) 判断目录或文件是否相同
os.path.sameopenfile(fp1, fp2) 判断fp1和fp2是否指向同一文件
os.path.samestat(stat1, stat2) 判断stat tuple stat1和stat2是否指向同一个文件
os.path.split(path) 把路径分割成 dirname 和 basename,返回一个元组
os.path.splitdrive(path) 一般用在 windows 下,返回驱动器名和路径组成的元组
os.path.splitext(path) 分割路径,返回路径名和文件扩展名的元组
os.path.splitunc(path) 把路径分割为加载点与文件
os.path.walk(path, visit, arg) 遍历path,进入每个目录都调用visit函数,visit函数必须有3个参数(arg, dirname, names),dirname表示当前目录的目录名,names代表当前目录下的所有文件名,args则为walk的第三个参数
os.path.supports_unicode_filenames 设置是否支持unicode路径名

 

实例

以下实例演示了 os.path 相关方法的使用:

#!/usr/bin/python
# -*- coding: UTF-8 -*-
 
import os
 
print( os.path.basename('/root/runoob.txt') )   # 返回文件名
print( os.path.dirname('/root/runoob.txt') )    # 返回目录路径
print( os.path.split('/root/runoob.txt') )      # 分割文件名与路径
print( os.path.join('root','test','runoob.txt') )  # 将目录和文件名合成一个路径

 

执行以上程序输出结果为:

runoob.txt
/root
('/root', 'runoob.txt')
root/test/runoob.txt

 

以下实例输出文件的相关信息。

#!/usr/bin/python
# -*- coding: UTF-8 -*-
 
import os
import time
 
file='/root/runoob.txt' # 文件路径
 
print( os.path.getatime(file) )   # 输出最近访问时间
print( os.path.getctime(file) )   # 输出文件创建时间
print( os.path.getmtime(file) )   # 输出最近修改时间
print( time.gmtime(os.path.getmtime(file)) )  # 以struct_time形式输出最近修改时间
print( os.path.getsize(file) )   # 输出文件大小(字节为单位)
print( os.path.abspath(file) )   # 输出绝对路径
print( os.path.normpath(file) )  # 规范path字符串形式

 

执行以上程序输出结果为:

1539052805.5735736
1539052805.5775735
1539052805.5735736
time.struct_time(tm_year=2018, tm_mon=10, tm_mday=9, tm_hour=2, tm_min=40, tm_sec=5, tm_wday=1, tm_yday=282, tm_isdst=0)
7
/root/runoob.txt
/root/runoob.txt

 

 

 

本文:Python操作路径, pathlib 模块, pathlib替代os.path, pathlib模块用法详解, Python pathlib 教程

 

 

 

Add a Comment

Your email address will not be published.

Time limit is exhausted. Please reload CAPTCHA.