Python3标准库:pathlib文件系统路径作为对象

1. pathlib文件系统路径作为对象

pathlib模块提供了一个面向对象API来解析、建立、测试和处理文件名和路径,而不是使用底层字符串操作。

1.1 路径表达

pathlib包含一些类来管理使用POSIX标准或Microsoft Windows语法格式化的文件系统路径。这个模块包含一些“纯”类,会处理字符串但不与实际的文件系统交互,另外还包含一些“具体”类,它们扩展了API,以包含可以反映或修改本地文件系统上数据的操作。

纯类PurePosixPath和PureWindowsPath可以在任意操作系统上实例化和使用,因为它们只处理文件名和目录名。要实例化一个具体类来处理真正的文件系统,需要使用Path得到一个PosixPath或WindowsPath,这取决于具体的平台。

1.2 建立路径

要实例化一个新路径,可以提供一个字符串作为第一个参数。路径对象的字符串表示就是这个名值。要创建一个新路径来指定相对于已有路径的一个值,可以使用/操作符扩展这个路径。这个操作符的参数可以是一个字符串,也可以是另一个路径对象。

import pathlib

usr = pathlib.PurePosixPath('/usr')
print(usr)

usr_local = usr / 'local'
print(usr_local)

usr_share = usr / pathlib.PurePosixPath('share')
print(usr_share)

root = usr / '..'
print(root)

etc = root / '/etc/'
print(etc)

如示例输出中root的值所示,这个操作符会组合所提供的路径值,但是在包含父目录引用“..”时没有对结果进行规范化。不过,如果在一个路径段以路径分隔符开头,那么与os.path.join()中一样,会把它解释为一个新的“根”引用。会从路径值中间删除额外的路径分隔符,如这里的etc示例所示。

具体路径类包括一个用于规范化路径resolve()方法,它会在文件系统中查找目录和符号链接,并生成一个名指示的绝对路径。 

import pathlib

usr_local = pathlib.Path('/usr/local')
share = usr_local / '..' / 'share'
print(share.resolve())

这里相对路径被转换为绝对路径E:\usr\shar。如果输入路径包含符号链接,那么它们也会展开,以使规范化的路径直接指示目标。

要想在路径段提前不可知时建立路径,可以使用joinpath(),并传入各个路径段作为一个单独的参数。 

import pathlib

root = pathlib.PurePosixPath('/')
subdirs = ['usr', 'local']
usr_local = root.joinpath(*subdirs)
print(usr_local)

与/操作符一样,调用joinpath()会创建一个新实例。

给定一个现有的路径对象,可以很容易地建立一个与它稍有差别的新对象,如指示同一个目录中的另一个文件。可以使用with_name()创建一个新路径,将一个路径中的部分替换为另一个不同的文件名。使用with_suffix()也可以创建一个新路径,将文件名的扩展名替换为一个不同的值。 

import pathlib

ind = pathlib.PurePosixPath('source/pathlib/index.rst')
print(ind)

py = ind.with_name('pathlib_from_existing.py')
print(py)

pyc = py.with_suffix('.pyc')
print(pyc)

这两个方法都返回新对象,原来的对象仍保持不变。

1.3 解析路径

路径对象提供了一些方法和属性可以从路径名中抽取出部分值。例如,parts属性可以生成根据路径分隔符解析得到的一个路径段序列。 

路径对象具有从名称中提取部分值的方法和属性。例如,parts属性可以生成根据路径分隔符值解析得到的一个路径段序列。

import pathlib

p = pathlib.PurePosixPath('/usr/local')
print(p.parts)

这个序列是一个元组,反映了路径实例的不可变性。

有两种方法可以从一个给定的路径对象在文件系统层次结构中“向上”导航。parent属性指示一个新的路径实例,对应包含给定路径(os.path.dirname()返回的值)的目录。parents属性是一个迭代器,会生成一系列父目录引用,在路径层次结构中不断“向上”,直到到达文件系统的根目录。 

import pathlib

p = pathlib.PurePosixPath('/usr/local/lib')

print('parent: {}'.format(p.parent))

print('\nhierarchy:')
for up in p.parents:
    print(up)

这个例子迭代处理parents属性并打印成员值。

可以通过路径对象的属性来访问路径的其他部分。Name属性包含路径的最后一部分,即最后一个路径分隔符后面的部分(与os.path.basename()生成的值相同)。suffix属性包含扩展名分隔符后面的值,stem属性包含名字中后缀之前的部分。 

import pathlib

p = pathlib.PurePosixPath('./source/pathlib/pathlib_name.py')
print('path  : {}'.format(p))
print('name  : {}'.format(p.name))
print('suffix: {}'.format(p.suffix))
print('stem  : {}'.format(p.stem))

尽管suffix和stem的值与os.path.splitext()生成的值类似,但这些值只是基于name的值,而不是完整路径。

1.4 创建具体路径

可以由字符串参数创建具体Path类的实例,字符串参数可能指示文件系统中一个文件、目录或符号链接的名字(或可能的名字)。这个类还提供了很多便利方法,可以使用常用位置(如当前工作目录和用户的主目录)建立路径实例,这些常用位置可能会改变。

import pathlib

home = pathlib.Path.home()
print('home: ', home)

cwd = pathlib.Path.cwd()
print('cwd : ', cwd)

这两个方法都会创建预填充一个绝对文件系统引用的Path实例。

1.5 目录内容 

可以使用3个方法来访问目录列表以及发现文件系统中的文件名。iterdir()是一个生成器,会为包含目录中的每个元素生成一个新的path实例。

import pathlib

p = pathlib.Path('.')

for f in p.iterdir():
    print(f)

如果Path不指示一个目录,则iterdir()会产生NotADirectoryError。

可以使用glob()找出与一个模式匹配的文件。 

import pathlib

p = pathlib.Path('..')

for f in p.glob('*.py'):
    print(f)

这个例子展示了脚本父目录中的所有py文件。

 glob处理器支持使用模式前缀**或者通过调用rglob()而不是glob()来完成递归扫描。

import pathlib

p = pathlib.Path('..')

for f in p.rglob('*.py'):
    print(f)

由这个例子从父目录开始,所以必须通过一个递归搜索来查找与*.py匹配的示例文件。

1.6 读写文件

每个Path实例都包含一些方法来处理所指示文件的内容。要直接获取内容,可以使用read_bytes()或read_text()。要写入文件,可以使用write_bytes()或write_text()。可以使用open()方法打开文件并保存文件句柄,而不是向内置的open()函数传入文件名。  

import pathlib

f = pathlib.Path('example.txt')

f.write_bytes('This is the content'.encode('utf-8'))

with f.open('r', encoding='utf-8') as handle:
    print('read from open(): {!r}'.format(handle.read()))

print('read_text(): {!r}'.format(f.read_text('utf-8')))

这些便利方法会在打开文件和写入文件之前完成一些类型检查,除此之外,它们与直接操作是等价的。

1.7 管理目录和符号链接

可以用表示不存在的目录或符号链接的路径来创建关联的文件系统项。 

import pathlib

p = pathlib.Path('example_dir')

print('Creating {}'.format(p))
p.mkdir()

如果这个路径已经存在,则mkdir()会产生一个FileExistsError。

可以使用symlink_to()创建一个符号链接。这个链接根据路径的值命名,将指示symlink_to()参数给定的名字。 

import pathlib

p = pathlib.Path('example_link')

p.symlink_to('index.rst')

print(p)
print(p.resolve().name)

这个例子首先创建一个符号链接,然后使用resolve()读取这个链接来找出它指示的名字,并打印这个名字。

1.8 文件类型

Path实例包含一些方法来检查路径指示的文件的类型。下面这个例子测试它们。

import pathlib

p = pathlib.Path('demo.py')

hfmt = '{:18s}' + ('  {:>5}' * 6)
print(hfmt.format('Name', 'File', 'Dir', 'Link', 'FIFO', 'Block',
                  'Character'))
print()
fmt = '{:20s}  ' + ('{!r:>5}  ' * 6)
print(fmt.format(
    str(p),
    p.is_file(),
    p.is_dir(),
    p.is_symlink(),
    p.is_fifo(),
    p.is_block_device(),
    p.is_char_device(),
))

所有这些方法(is_dir()、is_file()、is_symlink()、is_fifo()、is_block_device()和is_char_device())都不带参数。

 

1.9 文件属性

可以使用方法stat()和lstat()来访问文件的有关详细信息(lstat()用于检查一个可能是符号链接的目标的状态)。这些方法生成的结果分别与os.stat()和os.lstat()相同。

import pathlib
import sys
import time

if len(sys.argv) == 1:
    filename = __file__
else:
    filename = sys.argv[1]

p = pathlib.Path(filename)
stat_info = p.stat()

print('{}:'.format(filename))
print('  Size:', stat_info.st_size)
print('  Permissions:', oct(stat_info.st_mode))
print('  Owner:', stat_info.st_uid)
print('  Device:', stat_info.st_dev)
print('  Created      :', time.ctime(stat_info.st_ctime))
print('  Last modified:', time.ctime(stat_info.st_mtime))
print('  Last accessed:', time.ctime(stat_info.st_atime))

取决于在哪里安装这个示例代码,输出可能有变化。

1.10 删除

提供了两个方法来删除文件系统中的对象,使用哪一个方法取决于具体的类型。要删除一个空目录,可以使用rmdir()。

import pathlib

p = pathlib.Path('example_dir')

print('Removing {}'.format(p))
p.rmdir()

如果后置推荐已经满足而目录不存在,则会产生一个FileNotFoundError异常。如果试图删除一个不为空的目录,则也会出现错误。

对于文件、符号链接和大多数其他路径类型,可以使用unlink()。

import pathlib

p = pathlib.Path('touched')

p.touch()

print('exists before removing:', p.exists())

p.unlink()

print('exists after removing:', p.exists())

用户必须有删除文件、符号链接、套接字或其他文件系统对象的权限。

posted @ 2020-03-12 09:19  SmallGrayCode  阅读(940)  评论(0编辑  收藏  举报