pathlib模块详解

pathlib模块

pathlib 模块的操作对象是各种操作系统中使用的路径

pathlib模块详解

“pure”类对字符串进行操作,不与实际的文件系统进行交互, 不关心路径是否真实有效。

  • PurePath 类会将路径看做是一个普通的字符串,它可以将多个指定的字符串拼接成适用于当前操作系统的路径格式,同时还可以判断任意两个路径是否相等。
  • PurePosixPath 和 PureWindowsPath 是 PurePath 的子类,前者用于操作 UNIX(包括 Mac OS X)风格的路径,后者用于操作 Windows 风格的路径。
  • Path 类和以上 3 个类不同,它操作的路径一定是真实有效的。Path 类提供了判断路径是否真实存在的方法。
  • PosixPath 和 WindowPath 是 Path 的子类,分别用于操作 Unix(Mac OS X)风格的路径和 Windows 风格的路径。

构建Path

构建扩展路径

要实例化路径,字符串作为参数。要创建引用相对于现有路径的值的新路径,请使用/运算符来扩展路径。运算符的参数可以是字符串或其他路径对象。

import pathlib

demo = pathlib.PureWindowsPath('/demo')
print(demo,type(demo))

data = demo / 'data'
print(data)

share = demo / pathlib.PureWindowsPath('share')
print(share)

parant = demo / '..'
print(parant)

images = parant / '/images/'
print(images)

执行结果

\demo <class 'pathlib.PureWindowsPath'>

\demo\data

\demo\share

\demo\..

\images

解析路径

操作符按照给定的方式组合路径值,并且在包含父目录引用“..”的情况下不会对结果进行解析。

具体路径类的resolve()方法,通过查看目录和符号链接的文件系统来解析路径,并生成名称引用的绝对路径。

import pathlib

data = pathlib.Path('/demo/data')
share = data / '..' / 'share'
print(type(share.resolve()))
print(share.resolve())

 

执行结果

<class 'pathlib.WindowsPath'>

E:\demo\share

 

组合路径

joinpath()可以组合路径。

import pathlib

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

执行结果

/windows/system

 

替换路径

使用with_name()创建新路径,用不同的文件名替换路径的名称部分。 使用Use with_suffix()创建新路径,用不同的值替换文件名的扩展名。

import pathlib

ind = pathlib.PureWindowsPath('source/images/img.jpg')
print(ind)

img_jpg = ind.with_name('image_dog.jpg')
print(img_jpg)

img_png = img_jpg.with_suffix('.png')
print(img_png)

 

执行结果

source\images\img.jpg

source\images\image_dog.jpg

source\images\image_dog.png

 

解析路径

Path对象具有用于从名称中提取部分值的方法和属性。

路径分割

例如,parts属性会生成一系列基于路径分隔符值解析的路径段。

import pathlib

p = pathlib.PureWindowsPath('/data/audio')
print(p.parts)

执行结果

('\\', 'data', 'audio')

向上导航

有两种方法可以从给定的路径对象中“向上”导航文件系统层次结构。

parent属性引用包含路径的目录的新路径实例,即os.path.dirname()返回的值。parents属性是迭代器,它产生父目录引用,不断地向上“提升”路径层次直到到达根目录。

import pathlib
p = pathlib.PureWindowsPath('/usr/local/lib')
print('parent: {}'.format(p.parent))
print('hierarchy:')
for up in p.parents:
    print(up)

执行结果

parent: \usr\local

hierarchy:

\usr\local

\usr

\

 

路径属性

路径的其他部分可以通过路径对象的属性来访问。

name属性保存最后一个路径分隔符后的最后一部分路径。

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))

执行结果

path  : source/pathlib/pathlib_name.py

name  : pathlib_name.py

suffix: .py

stem  : pathlib_name

 

 

创建Concrete路径

Concrete Path类的实例可以通过引用文件系统上的文件,目录或符号链接的名称的字符串参数来创建。 该类还提供了几种便捷方法来构建使用常用位置(如当前工作目录和用户主目录)的实例。

import pathlib

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

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

执行结果

home:  C:\Users\Tom

cwd :  E:\Python\pythoncode\lab_X\demo_pathlib

 

 

目录内容

有三种方法可以访问目录列表,以发现文件系统上可用文件的名称。 iterdir()是生成器,为包含目录中的每个项目生成新的Path实例。

import pathlib

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

for child in cwd.iterdir():
    print(child)

执行结果

cwd :  E:\Python\pythoncode\lab_X\demo_pathlib

E:\Python\pythoncode\lab_X\demo_pathlib\demo_01.py

E:\Python\pythoncode\lab_X\demo_pathlib\demo_02.py

E:\Python\pythoncode\lab_X\demo_pathlib\demo_03.py

E:\Python\pythoncode\lab_X\demo_pathlib\demo_04.py

E:\Python\pythoncode\lab_X\demo_pathlib\demo_05.py

E:\Python\pythoncode\lab_X\demo_pathlib\demo_06.py

E:\Python\pythoncode\lab_X\demo_pathlib\demo_07.py

E:\Python\pythoncode\lab_X\demo_pathlib\demo_08.py

E:\Python\pythoncode\lab_X\demo_pathlib\demo_09.py

 

匹配查找

使用glob()仅查找匹配模式的文件。

import pathlib

p = pathlib.Path('.')

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

执行结果

demo_10.py

递归扫描

glob处理器支持使用模式前缀**或通过调用rglob()来进行递归扫描。

import pathlib

p = pathlib.Path.home()

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

执行结果

C:\Users\Tom\.AndroidStudio3.2\system\log\idea_updater_error.log

C:\Users\Tom\.AndroidStudio3.5\system\log\idea.log

C:\Users\Tom\.docker\application-template\logs\com.docker.backend.log

C:\Users\Tom\.gradle\daemon\4.6\daemon-10012.out.log

 

下面的两种用法也实现了类似的功能:

import pathlib
p = pathlib.Path('..')

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

 

 

import pathlib
p = pathlib.Path('..')

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

上面在指定目录中查找特定类型的文件,或许是pathlib中最有用的功能了。

 

读写文件

每个Path实例都包含处理它所引用的文件内容的方法。

read_bytes()read_text()立即检索内容。

write_bytes()write_text()写入文件。

open()打开文件并保留文件句柄。

import pathlib

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

f.write_bytes('一条大河波浪宽,风吹稻花香两岸'.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')))

 

执行结果

read from open(): '一条大河波浪宽,风吹稻花香两岸'

read_text(): '一条大河波浪宽,风吹稻花香两岸'

 

 

目录和符号链接

目录创建

mkdir()不存在的目录或符号链接的路径可用于创建。

如果路径已经存在,mkdir()会引发一个FileExistsError。

import pathlib
p = pathlib.Path('example_dir')

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

 

第一次执行结果

Creating example_dir

第二次执行结果

Creating example_dir

Traceback (most recent call last):

  File "E:/Python/pythoncode/lab_X/demo_pathlib/demo_15.py", line 26, in <module>

    p.mkdir()

  File "d:\python\python36\Lib\pathlib.py", line 1226, in mkdir

    self._accessor.mkdir(self, mode)

  File "d:\python\python36\Lib\pathlib.py", line 387, in wrapped

    return strfunc(str(pathobj), *args)

FileExistsError: [WinError 183] 当文件已存在时,无法创建该文件。: 'example_dir'

 

创建符号链接

使用symlink_to() 创建符号链接。该链接将根据路径的值进行命名,并将引用作为symlink_to()的参数的名称。

import pathlib

p = pathlib.Path('example_link')
p.symlink_to('example.txt')
print(p)
print(p.resolve().name)

执行结果

example_link

example.txt

 

文件类型

Path实例包含几种用于测试路径引用的文件类型的方法。

本示例创建了多个不同类型的文件,并测试这些文件以及本地操作系统上可用的一些其他设备特定的文件。

import itertools
import os
import pathlib

root = pathlib.Path('test_files')

# Clean up from previous runs.
if root.exists():
    for f in root.iterdir():
        f.unlink()
else:
    root.mkdir()

# Create test files
(root / 'file').write_text(
    'This is a regular file', encoding='utf-8')
(root / 'symlink').symlink_to('file')
#os.mkfifo(str(root / 'fifo'))

# Check the file types
to_scan = itertools.chain(
    root.iterdir(),
    [pathlib.Path('/dev/disk0'),
     pathlib.Path('/dev/console')],
)
hfmt = '{:18s}' + ('  {:>5}' * 6)
print(hfmt.format('Name', 'File', 'Dir', 'Link', 'FIFO', 'Block',
                  'Character'))

fmt = '{:20s}  ' + ('{!r:>5}  ' * 6)
for f in to_scan:
    print(fmt.format(
        str(f),
        f.is_file(),
        f.is_dir(),
        f.is_symlink(),
        f.is_fifo(),
        f.is_block_device(),
        f.is_char_device(),
    ))

执行结果

Name                 File    Dir   Link   FIFO  Block  Character

test_files\file        True  False  False  False  False  False 

test_files\symlink     True  False   True  False  False  False 

\dev\disk0            False  False  False  False  False  False 

\dev\console          False  False  False  False  False  False

 

 

文件属性

有关文件的详细信息可以使用stat() 或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))

执行结果

  Size: 1358

  Permissions: 0o100666

  Owner: 0

  Device: 18467

  Created      : Wed Aug 19 07:32:07 2020

  Last modified: Wed Aug 19 07:43:32 2020

  Last accessed: Wed Aug 19 07:43:32 2020

 

要更简单地访问有关文件所有者的信息,请使用owner()group()

import pathlib
p = pathlib.Path(__file__)
print('{} is owned by {}/{}'.format(p, p.owner(), p.group()))

stat() 返回数字,这些方法将查找与ID相关联的名称。

touch()方法与Unix命令touch类似,用于创建文件或更新现有文件的修改时间和权限。

import pathlib
import time

p = pathlib.Path('touched')
if p.exists():
    print('already exists')
else:
    print('creating new')

p.touch()
start = p.stat()

time.sleep(1)

p.touch()
end = p.stat()

print('Start:', time.ctime(start.st_mtime))
print('End  :', time.ctime(end.st_mtime))

执行结果

creating new

Start: Wed Aug 19 07:48:48 2020

End  : Wed Aug 19 07:48:49 2020

 

 

 

权限

在类Unix系统上,可以使用chmod()更改文件权限,将模式作为整数传递。模式值可以使用stat模块中定义的常量来构造。这个例子切换用户的执行权限位。

脚本假定它具有运行时修改文件模式所需的权限。

import os
import pathlib
import stat

# Create a fresh test file.
f = pathlib.Path('pathlib_chmod_example.txt')
if f.exists():
    f.unlink()
f.write_text('contents')

# Determine what permissions are already set using stat.
existing_permissions = stat.S_IMODE(f.stat().st_mode)
print('Before: {:o}'.format(existing_permissions))

# Decide which way to toggle them.
if not (existing_permissions & os.X_OK):
    print('Adding execute permission')
    new_permissions = existing_permissions | stat.S_IXUSR
else:
    print('Removing execute permission')
    # use xor to remove the user execute permission
    new_permissions = existing_permissions ^ stat.S_IXUSR

# Make the change and show the new value.
f.chmod(new_permissions)
after_permissions = stat.S_IMODE(f.stat().st_mode)
print('After: {:o}'.format(after_permissions))

执行结果

Before: 666

Adding execute permission

After: 666

 

删除

有两种从文件系统中删除东西的方法,具体取决于类型。

删除空目录

要删除空目录,请使用rmdir()

import pathlib

p = pathlib.Path('example_dir')
print('Removing {}'.format(p))
p.rmdir()

 

执行结果

Removing example_dir

如果目录不存在,则会引发FileNotFoundError异常。尝试删除非空的目录也是错误的。

删除链接

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

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

import pathlib

p = pathlib.Path('touched')
p.touch()
print('exists before removing:', p.exists())
p.unlink()
print('exists after removing:', p.exists())

执行结果

exists before removing: True

exists after removing: False

相关文章: