Node.js 工具模块 Node.js path 模块提供了一些用于处理文件路径的小工具,我们可以通过以下方式引入该模块: var path = require("path")…
Python操作路径, pathlib 模块, pathlib替代os.path, pathlib模块用法详解, Python pathlib 教程
pathlib 库从 python3.4 开始,到 python3.6 已经比较成熟。如果你的新项目可以直接用 3.6 以上,建议用 pathlib。相比于老式的 os.path 有几个优势:
- 老的路径操作函数管理比较混乱,有的是导入 os, 有的又是在 os.path 当中,而新的用法统一可以用 pathlib 管理。
- 老用法在处理不同操作系统 win,mac 以及 linux 之间很吃力。换了操作系统常常要改代码,还经常需要进行一些额外操作。
- 老用法主要是函数形式,返回的数据类型通常是字符串。但是路径和字符串并不等价,所以在使用 os 操作路径的时候常常还要引入其他类库协助操作。新用法是面向对象,处理起来更灵活方便。
- pathlib 简化了很多操作,用起来更轻松。
举个例子, 把所有的 txt 文本全部移动到 archive 目录当中(archive 目录必须存在)。
使用原来的用法:
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
的核心
安装
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 教程