# Python `pathlib`教程

> 原文： [http://zetcode.com/python/pathlib/](http://zetcode.com/python/pathlib/)

Python `pathlib`教程展示了如何通过`pathlib`模块使用 Python 中的文件和目录。

`pathlib`是一个 Python 模块，提供用于处理文件和目录的对象 API。 `pathlib`是标准模块。

`Path`是使用文件的核心对象。

```py
$ pip install prettytable
$ pip install more_itertools

```

在本教程中，我们还将使用`prettytable`和`more_itertools`。

`words.txt`

```py
blue
forest
sky
ocean
rabbit
clue

```

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

## `Path.cwd`和`home`

我们通过`cwd()`获得当前工作目录，并通过`home()`获得主目录。

`cwd_home.py`

```py
#!/usr/bin/env python

from pathlib import Path

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

```

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

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

```

这是一个示例输出。

## 变更目录

我们使用`os'` `chdir()`进入另一个目录。

`change_dir.py`

```py
#!/usr/bin/env 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 程序内部更改目录。

```py
$ 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`

```py
#!/usr/bin/env python

from pathlib import Path

path = Path.cwd() / 'new'

path.mkdir()

```

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

## 复制文件

借助`shutil`模块，我们复制了一个文件。

`copy_file.py`

```py
#!/usr/bin/env python

from pathlib import Path
from shutil import copyfile

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

copyfile(source, destination)

```

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

```py
source = Path('words.txt')

```

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

## 连接路径

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

`join_path.py`

```py
#!/usr/bin/env python

from pathlib import Path

path = Path.home()

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

print(docs)
print(pictures)

```

在示例中，我们使用`/`将两条路径连接在一起。

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

```

这是输出。

## `Path.touch`

`touch()`创建一个新的空文件； 它等效于 Linux touch 命令。

`touch.py`

```py
#!/usr/bin/python3

from pathlib import Path

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

```

我们创建一个新的空`myfile.txt`。

## `Path.rename`

`rename()`重命名文件或目录。

`rename.py`

```py
#!/usr/bin/env python

from pathlib import Path

path = Path('names.txt')

path.rename('mynames.txt')

```

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

## 路径名

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

`path_names.py`

```py
#!/usr/bin/env 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())

```

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

```py
$ 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 样式。

## 相对路径

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

换句话说，当我们位于`/home/users/jano/`目录中时，我们可以仅通过文件名`data.txt`来关联该文件，而无需指定完整路径。

`relative_path.py`

```py
#!/usr/bin/env 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)

```

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

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

```

这是输出。

## `Path.parent`

使用`parent()`和`parents()`，我们可以获得路径的逻辑父级。

`parents.py`

```py
#!/usr/bin/env 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))

```

该示例打印路径的父级。

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

```

我们可以得到父母的父母。

```py
$ 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:/')]

```

这是输出。

## 路径子元素

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

`parts.py`

```py
#!/usr/bin/env python

from pathlib import Path

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

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

```

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

```py
print(path.parts)

```

通过`parts`，可以访问路径的各种组件。

```py
print(path.drive)

```

`drive`给出一个代表驱动器号或名称的字符串（如果有）。

```py
print(path.root)

```

`root`给出一个表示（本地或全局）根的字符串（如果有）。

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

```

这是输出。

以下程序给出了路径的其他部分。

`parts2.py`

```py
#!/usr/bin/env 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)

```

该程序将打印词干，名称，后缀和锚点。

```py
$ 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`

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

`list_dirs.py`

```py
#!/usr/bin/env 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`

```py
#!/usr/bin/env 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()`文件。

## 路径遍历

球形模式使用通配符指定文件名集。 例如，`*.txt`表示所有名称以`.txt`结尾的文件。 `*`是代表任何字符串的通配符。 另一个常见的通配符是问号（？），代表一个字符。

路径提供`glob()`和`rglob()`。 后者用于递归`glob`。 它将`**/`添加到给定模式的前面。

`globbing.py`

```py
#!/usr/bin/env 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 文件。 请注意，此类操作可能非常耗时。

```py
for e in path.rglob('*.py'):
print(e)

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

```

这两个操作是等效的。

## 路径树

以下示例是一个工具，它以分层树结构输出指定目录的内容。

`tree.py`

```py
#!/usr/bin/env 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`目录的内容。

## 按扩展名计数文件

在以下示例中，我们按扩展名对所有文件进行计数。 我们将`collections`的`Counter`用于任务。

`count_files.py`

```py
#!/usr/bin/env 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`目录中按扩展名分组的文件进行计数。

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

```

在列表推导式中，我们确保路径对象是带有`is_file()`的文件，并且该文件具有`en`扩展名。 文件可能没有扩展名。 特别是在 Unix 系统上。

```py
$ 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`

```py
#!/usr/bin/env python

from pathlib import Path

path = Path('words.txt')

content = path.read_text()
print(content)

```

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

```py
$ read_text.py
blue
forest
sky
ocean
rabbit
clue

```

这是输出。

## `Path.open`读取文件

`open()`会打开路径指向的文件，就像内置的`open()`函数一样。

`read_with_open.py`

```py
#!/usr/bin/env 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`

```py
#!/usr/bin/env 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 图片并将其以十六进制表示形式打印到终端。

## 路径`write_text`

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

`write_text.py`

```py
#!/usr/bin/python3

from pathlib import Path

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

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

```

该示例使用`touch()`创建一个新的空文件，并使用`write_text()`将一些文本数据写入该文件。

## 新文章

内容管理系统通常根据当年和月份将其新创建的文章放在目录结构中。 下一个示例对此进行了演示。

`new_article.py`

```py
#!/usr/bin/env 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}')

```

该程序要求用户输入。 它根据当前年份和月份创建一个新的文本文件。

## `PrettyTable`示例

处理文件和目录时，可以使用`PrettyTable`模块获得更好的输出。

`simple_table.py`

```py
#!/usr/bin/env 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)

```

该示例在一个漂亮的表中显示“文档”内的所有文本文件。 该表包含三列：文件名，大小和创建日期。

```py
$ 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`模块。

您可能也对以下相关教程感兴趣： [PrettyTable 教程](/python/prettytable/)， [Python `argparse`教程](/python/argparse/)， [Python 教程](/lang/python/)。