ZetCode

Python pathlib

最后修改于 2024 年 1 月 29 日

Python pathlib 教程演示了如何使用 pathlib 模块在 Python 中处理文件和目录。

pathlib 是一个 Python 模块,它提供了一个面向对象的 API 来处理文件和目录。pathlib 是一个标准模块。

Path 是处理文件的核心对象。

$ pip install prettytable
$ pip install more_itertools

在本文中,我们还将使用 prettytablemore_itertools

words.txt
blue
forest
sky
ocean
rabbit
clue

一些示例使用这个简单的文本文件。

Path cwd 和 home

我们使用 cwd 获取当前工作目录,使用 home 获取主目录。

cwd_home.py
#!/usr/bin/python

from pathlib import Path

print(f"Current directory: {Path.cwd()}")
print(f"Home directory: {Path.home()}")

该示例打印当前工作目录和主目录。

$ cwd_home.py
Current directory: C:\Users\Jano\Documents\pyprogs\pathlib
Home directory: C:\Users\Jano

Python pathlib 当前文件

__file__ 提供当前运行程序的路径。

current.py
#!/usr/bin/python

from pathlib import Path

p = Path(__file__)
print(p)

该示例打印程序的路径。

$ ./current.py 
/home/jano/Documents/prog/python/tmp/current.py

Python pathlib 更改目录

我们使用 oschdir 进入另一个目录。

change_dir.py
#!/usr/bin/python

from pathlib import Path
from os import chdir

path = Path('..')

print(f'Current working directory: {path.cwd()}')

chdir(path)

print(f'Current working directory: {path.cwd()}')

chdir('..')

我们更改当前工作目录。请注意,目录仅在 Python 程序内部更改。

$ change_dir.py
Current working directory: C:\Users\Jano\Documents\pyprogs\pathlib
Current working directory: C:\Users\Jano\Documents\pyprogs

Path mkdir

使用 mkdir 创建一个新目录。

mkdir.py
#!/usr/bin/python

from pathlib import Path

path = Path.cwd() / 'new'

path.mkdir()

该示例在当前工作目录中创建一个新目录。

Python pathlib 复制文件

借助 shutil 模块,我们复制一个文件。

copy_file.py
#!/usr/bin/python

from pathlib import Path
from shutil import copyfile

source = Path('words.txt')
destination = Path('words_bck.txt')

copyfile(source, destination)

该示例复制了一个 words.txt 文件。

source = Path('words.txt')

通过将文件名传递给 Path 构造函数来创建一个文件对象。

连接路径

可以使用 / 运算符或 joinpath 方法连接路径。

join_path.py
#!/usr/bin/python

from pathlib import Path

path = Path.home()

docs = path / 'Documents'
pictures = path / 'Pictures'

print(docs)
print(pictures)

在示例中,我们使用 / 连接了两个路径。

$ join_path.py
C:\Users\Jano\Documents
C:\Users\Jano\Pictures

Path touch

touch 创建一个新空文件;它相当于 Linux 的 touch 命令。

touch.py
#!/usr/bin/python

from pathlib import Path

Path('myfile.txt').touch()

我们创建了一个新的空文件 myfile.txt

Path rename

rename 重命名文件或目录。

rename.py
#!/usr/bin/python

from pathlib import Path

path = Path('names.txt')

path.rename('mynames.txt')

该示例将当前工作目录中的 names.txt 重命名为 mynames.txt

Path 名称

我们使用绝对文件路径或相对路径来引用文件。路径有不同的表示方式;Windows 使用的文件路径与 Linux 不同。

path_names.py
#!/usr/bin/python

from pathlib import Path

path = Path('C:/Users/Jano/Downloads/wordpress-5.1.tar.gz')

print(path)
print(path.as_uri())
print(path.as_posix())

该示例显示了三种不同的文件路径结构。

$ path_names.py
C:\Users\Jano\Downloads\wordpress-5.1.tar.gz
file:///C:/Users/Jano/Downloads/wordpress-5.1.tar.gz
C:/Users/Jano/Downloads/wordpress-5.1.tar.gz

第一个是 Windows 文件路径。第二个是 URI 风格。第三个是 POSIX 风格。

Path relative_to

相对路径 从某个给定的工作目录开始,避免了提供完整绝对路径的需要。例如,从 /home/users/jano/ 目录的角度来看,data.txt 是到 /home/users/jano/data.txt 的相对路径。

换句话说,当我们位于 /home/users/jano/ 目录时,我们可以通过文件名 data.txt 简单地引用该文件,而无需指定完整路径。

relative_path.py
#!/usr/bin/python

from pathlib import Path

path = Path('C:/Users/Jano/Downloads/wordpress-5.1.tar.gz')

home = Path.home()

relative = path.relative_to(home)
print(relative)

该示例打印了给定主目录的存档文件的相对路径。

$ relative_path.py
Downloads\wordpress-5.1.tar.gz

Path parents

使用 parentparents,我们可以获取路径的逻辑父目录。

parents.py
#!/usr/bin/python

from pathlib import Path

path = Path('C:/Users/Jano/Documents')

print(f"The parent directory of {path} is {path.parent}")
print(f"The parent of the parent of {path} is {path.parent.parent}")

print(f"All the parents of {path.parent}: ")

print(list(path.parents))

该示例打印路径的父目录。

print(f"The parent of the parent of {path} is {path.parent.parent}")

我们可以获取父目录的父目录。

$ parents.py
The parent directory of C:\Users\Jano\Documents is C:\Users\Jano
The parent of the parent of C:\Users\Jano\Documents is C:\Users
All the parents of C:\Users\Jano:
[WindowsPath('C:/Users/Jano'), WindowsPath('C:/Users'), WindowsPath('C:/')]

Path parts

路径由子元素组成,例如驱动器或根目录。

parts.py
#!/usr/bin/python

from pathlib import Path

path = Path('C:/Users/Jano/Documents')

print(path.parts)
print(path.drive)
print(path.root)

程序打印路径的某些部分。

print(path.parts)

parts 允许访问路径的各种组件。

print(path.drive)

drive 提供一个字符串,表示驱动器字母或名称(如果存在)。

print(path.root)

root 提供一个字符串,表示(本地或全局)根目录(如果存在)。

$ parts.py
('C:\\', 'Users', 'Jano', 'Documents')
C:
\

以下程序提供了路径的其他部分。

parts2.py
#!/usr/bin/python

from pathlib import Path
import os

path = Path('C:/Users/Jano/Downloads/wordpress-5.1.tar.gz')

print(f"The stem is: {path.stem}")
print(f"The name is: {path.name}")
print(f"The suffix is: {path.suffix}")
print(f"The anchor is: {path.anchor}")

print(f"File name: {os.path.splitext(path.stem)[0]}")

print("The suffixes: ")
print(path.suffixes)

该程序打印文件名、名称、后缀(多个)和锚点。

$ parts2.py
The stem is: wordpress-5.1.tar
The name is: wordpress-5.1.tar.gz
The suffix is: .gz
The anchor is: C:\
File name: wordpress-5.1
The suffixes:
['.1', '.tar', '.gz']

Path 列出目录

iterdir 产生目录内容的路径对象。

list_dirs.py
#!/usr/bin/python

from pathlib import Path

path = Path('C:/Users/Jano/Documents')

dirs = [e for e in path.iterdir() if e.is_dir()]
print(dirs)

该示例打印指定目录的子目录。我们使用 is_dir 检查路径对象是否为目录。

以下示例打印指定目录内的文件。

list_files.py
#!/usr/bin/python

from pathlib import Path

path = Path('C:/Users/Jano/Documents')

files = [e for e in path.iterdir() if e.is_file()]
print(files)

我们使用 is_file 检查路径对象是否为文件。

Path 模式匹配

Glob 模式使用通配符指定文件名集。例如,*.txt 代表所有文件名以 .txt 结尾的文件。* 是一个代表任何字符序列的通配符。另一个常见的通配符是问号(?),它代表一个字符。

Path 提供了 globrglob。后者用于递归模式匹配。它在给定模式前面添加 **/

globbing.py
#!/usr/bin/python

from pathlib import Path

path = Path('C:/Users/Jano/Documents/pyprogs')

for e in path.rglob('*.py'):
    print(e)
    
# for e in path.glob('**/*.py'):
#     print(e)    

该示例打印指定目录及其所有子目录中的所有 Python 文件。请注意,此类操作可能非常耗时。

for e in path.rglob('*.py'):
print(e)
    
# for e in path.glob('**/*.py'):
#     print(e)    

这两种操作是等效的。

Path 树状结构

以下示例是一个实用程序,它以分层树状结构输出指定目录的内容。

tree.py
#!/usr/bin/python

from pathlib import Path

def tree(directory):

    print(f'+ {directory}')

    for path in sorted(directory.rglob('*')):

        depth = len(path.relative_to(directory).parts)
        spacer = '    ' * depth

        # print(f'{spacer}+ {path.name}')

        if path.is_file():
            print(f'{spacer}f {path.name}')
        else:
            print(f'{spacer}d {path.name}')

path = Path.home() / 'Downloads'

tree(path)

该程序以树状结构输出 Downloads 目录的内容。

按扩展名统计文件

在下面的示例中,我们按扩展名统计所有文件。我们为此任务使用了 collectionsCounter

count_files.py
#!/usr/bin/python

import collections
from pathlib import Path

docs = Path.home() / 'Documents'

files = [path.suffix for path in docs.iterdir() if path.is_file() and path.suffix]
data = collections.Counter(files)

print(data)

for key, val in data.items(): 
    print(f'{key}: {val}')

该示例在 Documents 目录中按扩展名分组统计文件。

files = [path.suffix for path in docs.iterdir() if path.is_file() and path.suffix]

在列表推导式中,我们使用 is_file 确保路径对象是一个文件,并且该文件具有扩展名。文件可能没有扩展名;尤其是在 Unix 系统上。

$ count_files.py
Counter({'.txt': 7, '.pdf': 3, '.ini': 1, '.zip': 1, '.rtf': 1})
.pdf: 3
.txt: 7
.ini: 1
.zip: 1
.rtf: 1

Path read_text

read_text 将文件内容读取为字符串。文件被打开然后关闭。可选参数的含义与 open 中的相同。

read_text.py
#!/usr/bin/python

from pathlib import Path

path = Path('words.txt')

content = path.read_text()
print(content)

该示例使用 read_text 读取 words.txt 文件内容。

$ read_text.py
blue
forest
sky
ocean
rabbit
clue

合并两个文件

在以下示例中,我们从两个文本文件中读取数据并合并它们

words.txt
sky
cup
wind
snow
tree

这是 words.txt 文件。

adjectives.txt
blue
brown
strong
early
old

这是 adjectives.txt 文件。

merge_files.py
#!/usr/bin/python

import sys

from pathlib import Path
 
fname1 = sys.argv[1]
fname2 = sys.argv[2]

data1 = Path(fname1).read_text(encoding='utf-8').splitlines()
data2 = Path(fname2).read_text(encoding='utf-8').splitlines()

data = list(zip(data1, data2))

for e in data:
    print(' '.join(e))

我们将 adjectives.txt 与 words.txt 合并。

data1 = Path(fname1).read_text(encoding='utf-8').splitlines()
data2 = Path(fname2).read_text(encoding='utf-8').splitlines()

我们从这两个文件读取数据并将它们拆分成行。

data = list(zip(data1, data2))

我们将两个列表进行 zip 操作;我们得到一个元组对列表。

for e in data:
    print(' '.join(e))

最后,我们将每个元组对连接成一个最终字符串。

$ ./join_files.py adjectives.txt words.txt 
blue sky
brown cup
strong wind
early snow
old tree

Path 使用 open 读取文件

open 打开由路径指向的文件,就像内置的 open 函数一样。

read_with_open.py
#!/usr/bin/python

from pathlib import Path

path = Path('words.txt')

with path.open() as f: 
    lines = f.readlines()
    print(lines)

for line in lines:
    print(line.rstrip())

该示例使用 open 打开 words.txt 文件,并使用 readlines 读取内容。

Path 读取二进制文件

可以使用 read_bytes 读取图像等二进制文件。

read_bytes.py
#!/usr/bin/python

from pathlib import Path
import binascii
from more_itertools import sliced

path = Path('sid.jpg')

hexed = binascii.hexlify(path.read_bytes())
mybytes = list(sliced(hexed, 2))

i = 0

for b in mybytes:

    print(b.decode("utf-8") , end=' ')
    i += 1

    if (i % 30 == 0):
        print()

该示例读取一张 JPEG 图片,并以十六进制表示的形式打印到终端。

Path write_text

write_text 以文本模式打开文件,向其写入数据,然后关闭文件。

write_text.py
#!/usr/bin/python

from pathlib import Path

path = Path('myfile.txt')
path.touch()

path.write_text('This is myfile.txt')

该示例使用 touch 创建一个新空文件,并使用 write_text 向文件中写入一些文本数据。

新文章

内容管理系统通常会根据当前年份和月份将新创建的文章放入目录结构中。下一个示例演示了这一点。

new_article.py
#!/usr/bin/python

from pathlib import Path
import datetime

now = datetime.datetime.now()
year = now.year
month = now.month

name = input('Enter article name:')

path1 = Path('articles') / str(year) / str(month)
path1.mkdir(parents=True)

path2 = path1 /  f'{name}.txt'

path2.touch()

print(f'Article created at: {path2}')

该程序从用户那里获取输入。它根据当前年份和月份创建一个新的文本文件。

Python Pathlib PrettyTable 示例

当我们处理文件和目录时,我们可以使用 PrettyTable 模块获得更美观的输出。

simple_table.py
#!/usr/bin/python

from pathlib import Path
import datetime
from prettytable import PrettyTable

path = Path('C:/Users/Jano/Documents/')

pt = PrettyTable()
pt.field_names = ["File name", "Size", "Created"]

pt.align["File name"] = "l"
pt.align["Size"] = "r"
pt.align["Created"] = "l"

for e in path.glob('**/*.txt'):

    created = datetime.datetime.fromtimestamp(e.stat().st_ctime)
    size = e.stat().st_size
    pt.add_row([e.name, size, f"{created:%Y-%m-%d}"])
    
print(pt)

该示例在一个漂亮的表格中显示 Documents 目录内的所有文本文件。表格包含三列:文件名、大小和创建日期。

$ simple_table.py
+-------------------------------------------------------+-------+------------+
| File name                                             |  Size | Created    |
+-------------------------------------------------------+-------+------------+
| data.txt                                              |     0 | 2019-02-27 |
| eternal_return.txt                                    | 10467 | 2019-03-03 |
| potvrdenie.txt                                        |   773 | 2019-01-14 |
| text_processing.txt                                   |   750 | 2019-02-18 |
| website-inspire.txt                                   |    62 | 2019-03-03 |
| words.txt                                             |    31 | 2018-12-30 |
| Úvod do Symfony.txt                                   |  7613 | 2019-03-04 |
| robots.txt                                            |   240 | 2019-01-01 |
| robots.txt                                            |   240 | 2019-02-03 |
...

这是一个示例部分输出。

来源

Python pathlib — 面向对象的 Pyle 文件系统路径

在本文中,我们介绍了标准的 Python pathlib 模块。

作者

我叫 Jan Bodnar,是一名充满激情的程序员,拥有丰富的编程经验。我自 2007 年以来一直在撰写编程文章。迄今为止,我已撰写了 1,400 多篇文章和 8 本电子书。我在教学编程方面拥有十多年的经验。

列出所有 Python 教程