学习Pathlib与操作系统模块对文件和目录系统的操作

247 阅读15分钟

Pathlib与操作系统模块的文件和目录系统操作

在本教程中,我们将通过不同的可行背景来发现利用Python的Pathlib和OS包进行文件系统操作的一致决定。

我们将学习各种文件系统操作--不限于写和读一个文件,描述文件信息,重命名文件,创建目录等等。

前提条件

要跟上本教程,你需要有一些Python编程语言的基本知识。

目标

在本教程结束时,读者必须能够。

  • 利用 Pathlib 和操作系统模块来操作文件和目录路径。
  • 在文件系统操作中实施面向对象编程和函数式编程。
  • 将文件的元数据转换为基本的可读信息。
  • 操纵相对路径和绝对路径。
  • 理解OS和Pathlib模块可以独立适应的场景。

简介

文件系统的操作可以被描述为一种技术,可以用来控制或构建文件和目录。

有两种不同的方法来处理文件系统,使用。

  1. 功能性的依赖。
  2. 面向对象的概念。

本教程实际地强调了区分PathlibOS模块的不同情况。

操作系统模块

OS(操作系统)模块是一个基于Python的操作系统接口,在功能上提供了一种方便的方式,通过简单的函数调用来处理文件和目录。

此外,OS模块使我们有能力直接处理I/O任务。

Pathlib模块

Pathlib模块是一个面向对象的文件系统,提供代表文件系统路径的类,其语义适合各种操作系统。

操作系统和Pathlib模块之间的区别

在这一节中,我们将用可比较的代码片段实际说明Pathlib和OS模块之间的语义差异,以帮助你确定每个模块的适应性。

在你开始之前,让我们先导入库,如图所示。

import os
from pathlib import Path

使用OS和Pathlib查询当前路径

当你处理一个路径时,查询当前工作目录是一项基本任务。

使用这些库,你可以获取相对路径和绝对路径。

绝对路径给出了你正在工作的当前位置的完整描述,而相对路径是指与当前工作目录相对的位置。

注意:使用OS和Pathlib查询当前路径将返回一个绝对路径。

使用OS查询当前路径
import os
print(os.getcwd())

输出。

C:\Users\DELL\Desktop\practical_folder

输出返回你正在工作的绝对当前路径的一个字符串表示。

注意,如果你没有使用Windows操作系统,你的输出会有所不同(将包含正斜线/ )。

使用Pathlib查询当前路径
from pathlib import Path
print(Path().cwd())

输出。

WindowsPath('C:/Users/DELL/Desktop/practical_folder')

在这个例子中,输出返回你正在工作的当前位置的两个路径模块子类的实例之一。

  • 如果你使用的是Windows,它返回一个windows对象。
  • 如果你使用任何POSIX操作系统,如Linux和macOS,它返回一个POSIX路径对象。

然而,我们可以把这个对象转换成一个字符串,如图所示。

from pathlib import Path
print(str(Path().cwd()))

内置的字符串函数将帮助你把路径对象转换为字符串。

输出。

'C:\\Users\\DELL\\Desktop\\practical_folder'

注意前面两个输出中的\\/

导航到主目录

帮助从你的当前目录轻松导航到主目录。

使用操作系统模块导航到主目录

使用OS模块导航到用户的主目录路径,需要我们传递一个字符串表示的这些组件~~user 作为参数。

from os import path
print(path.expanduser('~'))

输出。

C:\Users\DELL
使用Pathlib模块来导航到主目录
from pathlib import Path
print(Path().home())

输出。

WindowsPath('C:/Users/DELL')

这个例子说明了Path().home() ,该函数返回一个路径的对象表示,可以转换为一个字符串值。

列出一个目录路径内容

在本节中,我们将概述当前目录、父目录和给定目录中的文件/目录。

使用OS模块来列出当前目录
import os
print(os.listdir())

输出。

['.ipynb_checkpoints', 'Untitled.ipynb']

这个例子返回一个包含给定或当前目录中的文件和文件夹的对象列表。

你也可以列出前一个目录或当前目录,一个例子将在接下来的片段中演示。

要列出前一个目录中的项目,需要你传递两个点的字符串作为参数,这就是所谓的相对路径模式。

import os
print(os.listdir('..'))

输出。

['.idea',
 'Anaconda3-2021.05-Windows-x86_64.exe',
 'Apps and Questions',
 'vector.lnk',
 'Visual Studio Code.lnk',
 'WPS Office.lnk',
 'WPS PDF.lnk']

在这个例子中,该函数返回一个包含文件和目录名称的字符串表示的列表。

使用Pathlib模块列出一个目录内容

使用Pathlib模块来列出一个给定目录中的项目,与OS模块中的前一个例子相比,多少有些不那么直接了当。

让我们考虑一下下面的例子。

from pathlib import Path
print(Path().iterdir())

输出。

<generator object Path.iterdir at 0x0000017A030A7120>

在这个例子中,该函数在堆内存地址旁边返回一个被生成器函数包裹的迭代器对象。为了勾勒出迭代器对象中的项目,我们基本上可以通过迭代器对象进行迭代,或者选择另一种方式,将其转换为一个列表对象。

对于这种情况,让我们把它转换成一个列表对象。

from pathlib import Path
print(list(Path().iterdir()))

输出。

[WindowsPath('.ipynb_checkpoints'), WindowsPath('Untitled.ipynb')]

这个例子说明了在给定的目录中有两个项目。

Pathlib也接受两个点的字符串作为参数,可以通过构造函数来迭代提示父目录。

from pathlib import Path
print(list(Path('..').iterdir()))

输出。

[WindowsPath('../.idea'),
 WindowsPath('../Anaconda3-2021.05-Windows-x86_64.exe'),
 WindowsPath('../Apps and Questions'),
 WindowsPath('../vector.lnk'),
 WindowsPath('../Visual Studio Code.lnk'),
 WindowsPath('../WPS Office.lnk'),
 WindowsPath('../WPS PDF.lnk')]

输出是提示父目录中的文件和目录在我的桌面目录中的列表。

然而,pathlib替代性地提供了Path.glob() 来列出给定或当前目录中的文件和目录,这个方法需要一个字符串参数来执行特定的任务。

利用glob方法列出一个相对的目录路径

glob方法可以用来对给定路径所代表的目录中的文件进行相对模式匹配。

from pathlib import Path
print(list(Path('..').glob('*')))

在这个例子中,传递给glob('*') 方法的星号指示该方法列出给定目录中的所有项目。

输出。

[WindowsPath('../.idea'),
 WindowsPath('../Anaconda3-2021.05-Windows-x86_64.exe'),
 WindowsPath('../Apps and Questions'),
 WindowsPath('../vector.lnk'),
 WindowsPath('../Visual Studio Code.lnk'),
 WindowsPath('../WPS Office.lnk'),
 WindowsPath('../WPS PDF.lnk')]

输出涵盖了给定目录中的项目的列表。

为了用Path.glob() 方法列出一个文件的具体模式,我们遵循以下命令。

from pathlib import Path
print(list(Path('..').glob('*.lnk')))

输出。

[WindowsPath('../vector.lnk'),
 WindowsPath('../Visual Studio Code.lnk'),
 WindowsPath('../WPS Office.lnk')]

它返回所有以给定模式结尾的文件。Pathlib模块还提供了PurePath.suffix()方法来执行同样的操作,而不一定要将其转换为列表。

创建一个目录和文件

在某些情况下,每当你写一个Python脚本时,你可能需要自动创建一个目录或文件。在这种情况下,我们将利用这个机会,从语义上说明我们如何在 python 中创建一个文件或目录。

使用OS模块创建一个文件
import os

os.mknod('script.py')
print(os.listdir())

os.mknod() 函数帮助你创建一个文件。如果该文件已经存在,它将引发一个FileExistError 异常,可以使用try-except 来处理。

注意:os.mknod() 函数只在Unix类型的操作系统中可用。

输出。

['script.py', 'main.py']
使用pathlib创建一个文件
from pathlib import Path

Path('new_script.py', exist_ok=True).touch()
print(list(Path('').iterdir()))

Pathlib为POSIX和Windows操作系统提供了Path.touch() 方法,就像os.mknod() 函数一样。

这个方法在创建一个文件的同时没有返回任何东西,这意味着我们需要遍历当前目录以确认文件是否被创建。

Path.touch() 来确认文件的创建是一种更简单、更有效的方法。

输出。

[WindowsPath('.ipynb_checkpoints'),
 WindowsPath('new_script.py'),
 WindowsPath('Untitled.ipynb')]
使用OS创建一个新的目录
import os
os.mkdir('Document')
使用pathlib创建一个新的指令
from pathlib import Path
print(Path('Movie').mkdir(exist_ok=True))

如果该目录已经存在,将产生一个FileExistError 。然而,你可以简单地传递exist_ok=True 参数来处理FileExistError 异常。

检查现有的文件或目录

我们可以通过手动导航到路径来检查一个文件是否已经存在,但是为了更方便,避免手动检查,我们可以使用OS和Pathlib来验证是否存在。

使用OS模块检查一个目录
import os
print(os.path.exists('Movie'))

根据目录是否已经存在,返回值将是一个布尔值。

输出。

True
使用Pathlib检查一个目录
from pathlib import Path
print(Path('Document').exists())

输出。

True

它返回True ,因为该目录存在。如果不是,它将返回False

重命名一个目录和文件

我们可以使用OS和Pathlib模块重命名一个文件或目录。

使用OS模块重命名一个目录
import os
os.rename("Movie", "NewMovie")

该函数返回void,目录名被重命名为给定的名称(第二个参数)。

如果你遍历当前目录或使用os.exists() 函数确认,你会注意到目录已被重命名。

使用Pathlib模块重命名一个目录
from pathlib import Path

target = Path('Data')
current =Path('Document')
print(Path.rename(current, target))

Path 类的Path.rename() 方法只接受一个路径对象,这就是你如果尝试了就不能传递一个字符串作为参数的原因,另外还有一个替代方法,你可以使用pathlib重命名一个文件或一个目录。我们将在下一个例子中尝试这个方法。

输出。

WindowsPath('Data')

该方法返回一个WindowsPath对象,其中包含目录的新名称。

另一种使用pathlib重命名文件或目录的方法是。

from pathlib import Path

target = Path('data_script.py')
current = Path('new_script.py')
print(current.rename(target))

输出。

WindowsPath('data_script.py')

该方法返回一个包含文件新名称的路径对象。

将路径组件连接在一起

OS和Pathlib模块提供了将两个目录路径连接起来的方法/函数。

用OS模块将路径连接在一起
import os

current_path = os.getcwd()
print(os.path.join(current_path, 'data_script.py'))

输出。

'C:\\Users\\DELL\\Desktop\\practical_folder\\data_script.py'

os.path.join() 函数给你提供了通过连接两个字符串把两个组件连在一起的能力。

其结果是一个串联的字符串。

使用pathlib模块将路径连接起来

pathlib模块的Purepath 类提供了将两个组件连接在一起的能力。

from pathlib import Path, PurePath
print(PurePath.joinpath(Path().cwd(),'Data'))

输出。

WindowsPath('C:/Users/DELL/Desktop/practical_folder/Data')

注意:PurePath.joinpath() 方法的第一个参数是一个路径对象,第二个参数是一个字符串。该方法并不检查作为第二个参数的路径是否存在。

Pathlib提供了一种替代方法,使用正斜线/ 操作符将各种组件连接在一起。

为了连接路径,我们使用正斜线运算符,分子中是PurePath 对象,分母中是字符串,如图所示。

from pathlib import PurePath, Path

path = PurePath(str(Path().cwd()))
print(path / 'Data')

输出。

PureWindowsPath('C:/Users/DELL/Desktop/practical_folder/Data')

它返回包含组合组件的类PurePath 的直接子类之一。

要在现有的路径上追加几个字符串,请按照所示的命令进行操作。

from pathlib import PurePath

path = PurePath('old')
print(path / 'new' / 'script.py')

输出。

PureWindowsPath('old/new/script.py')

查询路径以检索当前工作目录

我们可以使用pathlib或者OS模块来查询路径,以获取当前的工作目录,它返回最终文件或目录名称的字符串表示。

使用OS模块
import os
print(os.path.basename(os.getcwd()))

输出。

'practical_folder'

在这个例子中,函数的结果返回当前目录的基本名称,并以字符串表示。

使用pathlib模块
from pathlib import PurePath, Path
print(PurePath(Path().cwd() / 'data_script.py').name)

PurePath ,期望通过其构造函数传递一个路径对象或字符串,所以我们只是将文件名与当前目录结合起来,以避免打字的压力,也省去了调用PurePath.joinpath() 方法。

输出。

'data_script.py'

结果是最终组件的字符串表示,这个组件始终是一个文件。

删除一个目录

OS和Pathlib模块提供了一个方法或函数,有条件地删除一个目录。

这个条件表达了试图删除一个不是空的目录将导致一个错误,这基本上意味着你不能删除一个被占用的目录。

要做到这一点,你可以使用OS模块提供的os.remove() 函数或Pathlib模块提供的Path.unlink() 方法来删除一个文件或目录。

如果试图删除一个不存在的目录,将产生一个IsADirectoryError 异常。同样,如果一个不存在的文件被删除,将产生一个FileNotFoundError 异常。

用操作系统模块删除文件或目录
import os

first_dir = 'Data'
print(f'Does "{first_dir}" exist? \n', 'Yes!' if os.path.exists(first_dir) else 'No!')
os.rmdir(first_dir)
print(f'\nAfter deleting "{first_dir}".\n')
print(f'Does "{first_dir}" exist? \n', 'Yes!' if os.path.exists(first_dir) else 'No!')

此外,我们利用print() 语句中的os.path.exists() 函数来确认目录是否被删除。

如果目录成功被删除,响应将是Yes ,否则,响应将是No 。而且,如果该目录不存在,将引发一个FileExistError 异常。

输出。

Does "Data" exist?
Yes!
After deleting "Data".
Does "Data" exist?
No!
用pathlib模块删除文件或目录
from pathlib import Path

second_dir = 'NewMovie'
print(f'Does "{second_dir}" exist? \n', 'Yes!' if Path(second_dir).exists() else 'No!')
Path(second_dir).rmdir()
print(f'\nAfter deleting "{second_dir}".\n')
print(f'Does "{second_dir}" exist? \n', 'Yes!' if Path(second_dir).exists() else 'No!')

输出。

Does "NewMovie" exist?
Yes!
After deleting "NewMovie".
Does "NewMovie" exist?
No!

检索和转换一个文件信息

在本节中,我们将使用timedatetime 模块来转换和解释一个给定的文件信息。

使用OS模块来检索信息

OS模块提供了三个可以用来查询文件信息的函数,尽管我们将在本教程中使用最全面的一个。

import os

note_file = os.stat('Untitled.ipynb')
print(f'Size = {note_file.st_size}\nlast time accessed = {note_file.st_atime}\nlast time modified = {note_file.st_mtime}\ncreation time = {note_file.st_ctime}')

输出。

Size = 5694
last time accessed = 1642186406.360829
last time modified = 1642186405.3119907
creation time = 1641623379.0384889

在上面的例子中,我们查询了相应的属性,以获得它们代表文件元数据的区分状态。

  • st_size 包含以字节为单位的文件大小。
  • st_atime 包含最近一次访问给定文件的日期(秒)。
  • st_mtime 属性包含文件的最后修改日期(秒)。
  • st_ctime attribute在UNIX和Windows操作系统中的反应不同。在Windows中,它输出的是创建日期,而在UNIX中它输出的是更新日期。
  • st_birthtime 在UNIX操作系统上查询创建时间。
使用数据时间模块转换信息

datetime 模块转换文件的时间和日期,使输出结果对我们来说可读。

from datetime import datetime
import os

note_file = os.stat('Untitled.ipynb')
last_accessed = datetime.fromtimestamp(note_file.st_atime)
last_modified = datetime.fromtimestamp(note_file.st_mtime)
creation_date = datetime.fromtimestamp(note_file.st_ctime)
print(f'last time accessesd: {last_accessed}\nlast time modified: {last_modified}\ncreation time: {creation_date}')

输出。

last time accessesd: 2022-01-14 21:15:26.361177
last time modified: 2022-01-14 21:15:25.322196
creation time: 2022-01-08 07:29:39.038489
使用时间模块转换信息

时间模块不常用来转换文件的日期和时间信息。

import os, time

note_file = os.stat('Untitled.ipynb')
last_accessed = time.ctime(note_file.st_atime)
last_modified = time.ctime(note_file.st_mtime)
creation_date = time.ctime(note_file.st_ctime)
print(f'last time accessesd: {last_accessed}\nlast time modified: {last_modified}\ncreation time: {creation_date}')

输出。

last time accessesd: Fri Jan 14 21:17:26 2022
last time modified: Fri Jan 14 21:17:25 2022
creation time: Sat Jan 8 07:29:39 2022
使用pathlib模块来查询信息

Pathlib模块提供了Path.stat() 方法来检索关于一个给定文件的信息,该方法返回一个包含给定文件信息的os.stat_result 对象。

from pathlib import Path

recent_script = Path('new_script.ipynb').stat()
print(f'Size = {recent_script.st_size}\nlast time accesed = {recent_script.st_atime}\nlast time modified = {recent_script.st_mtime}\ncreation time = {recent_script.st_ctime}')

输出结果。

Size = 72
last time accessed = 1642193846.365352
last time modified = 1642193544.1581955
creation time = 1642193544.1562355

你可以按照上面2个关于格式转换的主题将日期和时间转换为可读格式。

查询文件扩展名

Pathlib和OS模块提供了一个函数或方法,允许我们查询文件扩展名。

使用OS模块来查询文件扩展名

OS模块提供了os.path.splitext() 函数来查询文件的扩展名。它将路径分割成一对,同时返回文件名和文件扩展名。

import os
print(os.path.splitext('Untitled.ipynb'))

输出。

('Untitled', '.ipynb')
使用pathlib模块查询文件扩展名

Pathlib提供了两个属性来分割文件扩展名和文件名。这些属性是Path.suffixPath.stem

Path.suffix 用于分割文件并检索文件扩展名,而Path.stem 用于分割文件以检索文件名。

from pathlib import Path

file = Path('new_script.ipynb')
print(f'File name: {file.stem}\nFile extension: {file.suffix}')

输出。

File name: new_script
File extension: .ipynb

注意:如果给定的文件没有扩展名,Path.suffix 属性将检索到一个空字符串。

Pathlib和OS模块的理论差异

说明OS和Pathlib模块之间的理论差异。

OS模块

  • 它提供了一个名为path 的子模块来操作普通的路径名,并提供直接的函数来执行I/O活动。
  • 它的基本函数大多返回一个字符串表示。
  • 它提供了不同的函数,可以对环境变量进行额外的操作,如设置环境,删除环境,以及更多操作。

Pathlib模块

  • 它提供了杰出的类,可以在各种操作系统上执行明确的系统操作,这清楚地表达了pathlib模块是不可移植的。
  • 这些方法通常返回与系统兼容的对象,如PurePathPosix、PosixPath、PurePathWindows和WindowsPath。
  • 列出一个目录的内容是一项繁琐的工作,因为它返回一个需要迭代的生成器,以输出可读的字符串。
  • pathlib中的path类提供了一种方法来创建一个具有不同扩展名的永久性空文件,这使得在python中处理文件系统的操作变得令人费解。
  • 它并没有对环境变量的操作做任何安排。

总结

在这一点上,你应该掌握了OS和Pathlib模块之间的区别。此外,你还会学到以下内容。

  • 在为文件系统操作选择合适的模块时,要有好的决策。
  • 如何使用文件系统操作。
  • 删除一个文件。
  • 识别相对路径和绝对路径之间的区别。
  • 使用时间和日期时间模块转换文件的日期属性。
  • 如何在区分的操作系统上进行路径操作。
  • 检索特定的文件信息。