Vuyisile Ndlovu
使用 Python 读写文件数据非常简单直接。要完成此操作,必须首先以适当的模式打开文件。以下是如何使用 Python 的 with open(...) as ... 模式打开文本文件并读取其内容的示例:
with open('data.txt', 'r') as f:
data = f.read()
open() 接收一个文件名和一个模式作为参数。r 以只读模式打开文件。若要向文件写入数据,请传入 w 作为参数:
with open('data.txt', 'w') as f:
data = 'some data to be written to the file'
f.write(data)
在上述示例中,open() 会以读取或写入模式打开文件,并返回一个文件句柄(本例中为 f),该句柄提供可用于向文件读取或写入数据的方法。
获取目录列表
假设当前工作目录下有一个名为 my_directory 的子目录,其内容如下:
my_directory/
├── sub_dir/
│ ├── bar.py
│ └── foo.py
├── sub_dir_b/
│ └── file4.txt
├── sub_dir_c/
│ ├── config.py
│ └── file5.txt
├── file1.py
├── file2.csv
└── file3.txt
内置的 os 模块提供了许多有用的函数,可用于列出目录内容并对结果进行筛选。要在文件系统中获取特定目录下所有文件和文件夹的列表,请在旧版 Python 中使用 os.listdir(),或在 Python 3 中使用 os.scandir()。如果你还需要获取文件和目录属性(如文件大小和修改日期),则推荐使用 os.scandir()。
在旧版 Python 中获取目录列表
在 Python 3 之前的版本中,获取目录列表的方法是使用 os.listdir():
>>> import os
>>> entries = os.listdir('my_directory/')
os.listdir() 返回一个 Python 列表,其中包含由路径参数指定的目录中的所有文件和子目录的名称:
>>> os.listdir('my_directory/')
['sub_dir_c', 'file1.py', 'sub_dir_b', 'file3.txt', 'file2.csv', 'sub_dir']
这样的目录列表不易阅读。使用循环打印 os.listdir() 调用的输出有助于整理内容:
>>> entries = os.listdir('my_directory/')
>>> for entry in entries:
... print(entry)
...
sub_dir_c
file1.py
sub_dir_b
file3.txt
file2.csv
sub_dir
在现代 Python 版本中获取目录列表
在现代 Python 版本中,os.listdir() 的替代方案是使用 os.scandir() 和 pathlib.Path()。
os.scandir() 于 Python 3.5 引入,并在 PEP 471 中有详细说明。与返回列表不同,os.scandir() 返回一个迭代器:
>>> import os
>>> entries = os.scandir('my_directory/')
>>> entries
<posix.ScandirIterator object at 0x7f5b047f3690>
ScandirIterator 指向当前目录中的所有条目。你可以遍历该迭代器的内容并打印出文件名:
import os
with os.scandir('my_directory/') as entries:
for entry in entries:
print(entry.name)
此处,os.scandir() 与 with 语句结合使用,因为它支持上下文管理器协议。使用上下文管理器可在迭代器耗尽后自动关闭迭代器并释放所获取的资源。结果会像 os.listdir() 示例一样打印出 my_directory/ 中的文件名:
sub_dir_c
file1.py
sub_dir_b
file3.txt
file2.csv
sub_dir
另一种获取目录列表的方法是使用 pathlib 模块:
from pathlib import Path
entries = Path('my_directory/')
for entry in entries.iterdir():
print(entry.name)
Path 返回的对象根据操作系统不同,可能是 PosixPath 或 WindowsPath 对象。
pathlib.Path() 对象具有 .iterdir() 方法,用于创建目录中所有文件和文件夹的迭代器。.iterdir() 生成的每个条目都包含有关该文件或目录的信息,例如其名称和文件属性。pathlib 首次在 Python 3.4 中引入,是 Python 的一个绝佳补充,它提供了面向对象的文件系统接口。
在上面的示例中,你调用 pathlib.Path() 并向其传递一个路径参数。接下来调用 .iterdir() 以获取 my_directory 中所有文件和目录的列表。
pathlib 提供了一组类,以简单、面向对象的方式实现路径上的大多数常见操作。使用 pathlib 与使用 os 中的函数相比,效率相当甚至更高。使用 pathlib 而非 os 的另一个好处是,它减少了操作文件系统路径所需的导入数量。
运行上述代码会产生以下输出:
sub_dir_c
file1.py
sub_dir_b
file3.txt
file2.csv
sub_dir
与 os.listdir() 相比,使用 pathlib.Path() 或 os.scandir() 是获取目录列表的首选方法,尤其是在你需要文件类型和文件属性信息时。pathlib.Path() 提供了 os 和 shutil 中的大部分文件和路径处理功能,且其方法比这些模块中的一些方法更高效。我们稍后将讨论如何获取文件属性。
以下是再次列出的目录列表函数:
| 函数 | 描述 |
|---|---|
os.listdir() |
返回目录中所有文件和文件夹的列表 |
os.scandir() |
返回一个包含目录中所有对象(包括文件属性信息)的迭代器 |
pathlib.Path.iterdir() |
返回一个包含目录中所有对象(包括文件属性信息)的迭代器 |
这些函数返回目录中的所有内容,包括子目录。这可能并不总是你想要的行为。下一节将展示如何过滤目录列表的结果。
列出目录中的所有文件
本节将展示如何使用 os.listdir()、os.scandir() 和 pathlib.Path() 打印出目录中的文件名。要从 os.listdir() 生成的目录列表中过滤掉目录并仅列出文件,请使用 os.path:
import os
# 使用 os.listdir 列出目录中的所有文件
basepath = 'my_directory/'
for entry in os.listdir(basepath):
if os.path.isfile(os.path.join(basepath, entry)):
print(entry)
这里,对 os.listdir() 的调用返回指定路径中的所有内容列表,然后通过 os.path.isfile() 过滤该列表,仅打印出文件而非目录。这会产生以下输出:
file1.py
file3.txt
file2.csv
使用 os.scandir() 或 pathlib.Path() 列出目录中的文件更为简便:
import os
# 使用 scandir() 列出目录中的所有文件
basepath = 'my_directory/'
with os.scandir(basepath) as entries:
for entry in entries:
if entry.is_file():
print(entry.name)
使用 os.scandir() 的优点是代码看起来更整洁、更易理解,尽管它比使用 os.listdir() 多了一行代码。对 ScandirIterator 中的每个项目调用 entry.is_file(),如果对象是文件则返回 True。打印目录中所有文件的名称会得到以下输出:
file1.py
file3.txt
file2.csv
以下是使用 pathlib.Path() 列出目录中文件的方法:
from pathlib import Path
basepath = Path('my_directory/')
files_in_basepath = basepath.iterdir()
for item in files_in_basepath:
if item.is_file():
print(item.name)
这里,你在 .iterdir() 生成的每个条目上调用 .is_file()。产生的输出与之前相同:
file1.py
file3.txt
file2.csv
如果将 for 循环和 if 语句合并为单个生成器表达式,上述代码可以更加简洁。Dan Bader 有一篇关于生成器表达式和列表推导式的优秀文章。
修改后的版本如下所示:
from pathlib import Path
# 使用 pathlib 列出目录中的所有文件
basepath = Path('my_directory/')
files_in_basepath = (entry for entry in basepath.iterdir() if entry.is_file())
for item in files_in_basepath:
print(item.name)
这会产生与前一个示例完全相同的输出。本节展示了使用 os.scandir() 和 pathlib.Path() 过滤文件或目录比结合使用 os.listdir() 和 os.path 更直观、更简洁。
列出子目录
要列出子目录而非文件,请使用以下方法之一。以下是使用 os.listdir() 和 os.path() 的方法:
import os
# 使用 os.listdir 列出所有子目录
basepath = 'my_directory/'
for entry in os.listdir(basepath):
if os.path.isdir(os.path.join(basepath, entry)):
print(entry)
以这种方式操作文件系统路径在多次调用 os.path.join() 时会很快变得繁琐。在我的计算机上运行此代码会产生以下输出:
sub_dir_c
sub_dir_b
sub_dir
以下是使用 os.scandir() 的方法:
import os
# 使用 scandir() 列出所有子目录
basepath = 'my_directory/'
with os.scandir(basepath) as entries:
for entry in entries:
if entry.is_dir():
print(entry.name)
与文件列表示例一样,这里你在 os.scandir() 返回的每个条目上调用 .is_dir()。如果条目是目录,.is_dir() 返回 True,并打印出目录名称。输出与上面相同:
sub_dir_c
sub_dir_b
sub_dir
以下是使用 pathlib.Path() 的方法:
from pathlib import Path
# 使用 pathlib 列出所有子目录
basepath = Path('my_directory/')
for entry in basepath.iterdir():
if entry.is_dir():
print(entry.name)
在 basepath 迭代器的每个条目上调用 .is_dir() 以检查条目是文件还是目录。如果条目是目录,则将其名称打印到屏幕上,产生的输出与前一个示例相同:
sub_dir_c
sub_dir_b
sub_dir
获取文件属性
Python 可以轻松检索文件属性,例如文件大小和修改时间。这是通过 os.stat()、os.scandir() 或 pathlib.Path() 完成的。
os.scandir() 和 pathlib.Path() 在获取目录列表的同时获取文件属性。这可能比使用 os.listdir() 列出文件,然后为每个文件获取文件属性信息更高效。
以下示例展示了如何获取 my_directory/ 中文件的最后修改时间。输出以秒为单位:
>>> import os
>>> with os.scandir('my_directory/') as dir_contents:
... for entry in dir_contents:
... info = entry.stat()
... print(info.st_mtime)
...
1539032199.0052035
1539032469.6324475
1538998552.2402923
1540233322.4009316
1537192240.0497339
1540266380.3434134
os.scandir() 返回一个 ScandirIterator 对象。ScandirIterator 对象中的每个条目都有一个 .stat() 方法,用于检索其指向的文件或目录的信息。.stat() 提供诸如文件大小和最后修改时间等信息。在上面的示例中,代码打印出 st_mtime 属性,即文件内容上次修改的时间。
pathlib 模块具有相应的文件信息检索方法,可产生相同的结果:
>>> from pathlib import Path
>>> current_dir = Path('my_directory')
>>> for path in current_dir.iterdir():
... info = path.stat()
... print(info.st_mtime)
...
1539032199.0052035
1539032469.6324475
1538998552.2402923
1540233322.4009316
1537192240.0497339
1540266380.3434134
在上面的示例中,代码遍历 .iterdir() 返回的对象,并对目录列表中的每个文件调用 .stat() 来检索文件属性。st_mtime 属性返回一个浮点值,表示自纪元以来的秒数。为了显示目的,你可以编写一个辅助函数将 st_mtime 返回的值转换为 datetime 对象:
from datetime import datetime
from os import scandir
def convert_date(timestamp):
d = datetime.utcfromtimestamp(timestamp)
formated_date = d.strftime('%d %b %Y')
return formated_date
def get_files():
dir_entries = scandir('my_directory/')
for entry in dir_entries:
if entry.is_file():
info = entry.stat()
print(f'{entry.name}\t Last Modified: {convert_date(info.st_mtime)}')
这将首先获取 my_directory 中的文件列表及其属性,然后调用 convert_date() 将每个文件的最后修改时间转换为人类可读的形式。convert_date() 使用 .strftime() 将秒数转换为字符串。
传递给 .strftime() 的参数如下:
%d:月份中的日期%b:月份的缩写形式%Y:年份
这些指令组合在一起会产生如下输出:
>>> get_files()
file1.py Last modified: 04 Oct 2018
file3.txt Last modified: 17 Sep 2018
file2.txt Last modified: 17 Sep 2018
将日期和时间转换为字符串的语法可能相当令人困惑。要了解更多相关信息,请查阅官方文档。另一个易于记忆的便捷参考是 http://strftime.org/。
创建目录
迟早,你编写的程序需要创建目录以在其中存储数据。os 和 pathlib 包含用于创建目录的函数。我们将考虑以下函数:
| 函数 | 描述 |
|---|---|
os.mkdir() |
创建单个子目录 |
pathlib.Path.mkdir() |
创建单个或多个目录 |
os.makedirs() |
创建多个目录,包括中间目录 |
创建单个目录
要创建单个目录,请将目录路径作为参数传递给 os.mkdir():
import os
os.mkdir('example_directory/')
如果目录已存在,os.mkdir() 会引发 FileExistsError。或者,你可以使用 pathlib 创建目录:
from pathlib import Path
p = Path('example_directory/')
p.mkdir()
如果路径已存在,mkdir() 会引发 FileExistsError:
>>> p.mkdir()
Traceback (most recent call last):
File '<stdin>', line 1, in <module>
File '/usr/lib/python3.5/pathlib.py', line 1214, in mkdir
self._accessor.mkdir(self, mode)
File '/usr/lib/python3.5/pathlib.py', line 371, in wrapped
return strfunc(str(pathobj), *args)
FileExistsError: [Errno 17] File exists: '.'
[Errno 17] File exists: '.'
为避免此类错误,可以在发生错误时捕获它并通知用户:
from pathlib import Path
p = Path('example_directory')
try:
p.mkdir()
except FileExistsError as exc:
print(exc)
或者,你可以通过向 .mkdir() 传递 exist_ok=True 参数来忽略 FileExistsError:
from pathlib import Path
p = Path('example_directory')
p.mkdir(exist_ok=True)
如果目录已存在,这不会引发错误。
创建多个目录
os.makedirs() 与 os.mkdir() 类似。两者之间的区别在于,os.makedirs() 不仅可以创建单个目录,还可以用于创建目录树。换句话说,它可以创建确保完整路径存在的任何必要中间文件夹。
os.makedirs() 类似于在 Bash 中运行 mkdir -p。例如,要创建像 2018/10/05 这样的目录组,只需执行以下操作:
import os
os.makedirs('2018/10/05')
这将创建一个嵌套目录结构,其中包含文件夹 2018、10 和 05:
.
└── 2018/
└── 10/
└── 05/
makedirs() 使用默认权限创建目录。如果需要使用不同权限创建目录,请调用 .makedirs() 并传入希望目录创建时使用的模式:
import os
os.makedirs('2018/10/05', mode=0o770)
这将创建 2018/10/05 目录结构,并赋予所有者和组用户读、写和执行权限。默认模式为 0o777,现有父目录的文件权限位不会更改。有关文件权限以及模式应用方式的更多详细信息,请参阅文档。
运行 tree 以确认已应用正确的权限:
$ tree -p -i .
[drwxrwx---] 2018
[drwxrwx---] 10
[drwxrwx---] 05
这会打印出当前目录的目录树。tree 通常用于以树状格式列出目录内容。向其传递 -p 和 -i 参数会以垂直列表形式打印出目录名称及其文件权限信息。-p 打印文件权限,-i 使 tree 生成无缩进线的垂直列表。
如你所见,所有目录都具有 770 权限。创建目录的另一种方法是使用 pathlib.Path 的 .mkdir():
import pathlib
p = pathlib.Path('2018/10/05')
p.mkdir(parents=True)
向 Path.mkdir() 传递 parents=True 使其创建目录 05 及创建有效路径所需的任何父目录。
默认情况下,如果目标目录已存在,os.makedirs() 和 Path.mkdir() 会引发 OSError。此行为可以通过在调用每个函数时传递 exist_ok=True 关键字参数来覆盖(自 Python 3.2 起)。
运行上述代码会一次性生成如下目录结构:
.
└── 2018/
└── 10/
└── 05/
我更喜欢使用 pathlib 创建目录,因为我可以使用同一个函数创建单个或嵌套目录。
文件名模式匹配
在使用上述方法之一获取目录中的文件列表后,你很可能希望搜索匹配特定模式的文件。
以下是你可用的方法和函数:
endswith()和startswith()字符串方法fnmatch.fnmatch()glob.glob()pathlib.Path.glob()
下面将逐一讨论这些方法。本节中的示例将在名为 some_directory 的目录上执行,其结构如下:
.
├── sub_dir/
│ ├── file1.py
│ └── file2.py
├── admin.py
├── data_01_backup.txt
├── data_01.txt
├── data_02_backup.txt
├── data_02.txt
├── data_03_backup.txt
├── data_03.txt
└── tests.py
如果你使用的是 Bash shell,可以使用以下命令创建上述目录结构:
$ mkdir some_directory
$ cd some_directory/
$ mkdir sub_dir
$ touch sub_dir/file1.py sub_dir/file2.py
$ touch data_{01..03}.txt data_{01..03}_backup.txt admin.py tests.py
这将创建 some_directory/ 目录,进入该目录,然后创建 sub_dir。下一行在 sub_dir 中创建 file1.py 和 file2.py,最后一行使用扩展创建所有其他文件。要了解更多关于 shell 扩展的信息,请访问此网站。
使用字符串方法
Python 有几个用于修改和操作字符串的内置方法。其中两种方法 .startswith() 和 .endswith() 在搜索文件名中的模式时非常有用。为此,首先获取目录列表,然后对其进行迭代:
>>> import os
>>> # 获取 .txt 文件
>>> for f_name in os.listdir('some_directory'):
... if f_name.endswith('.txt'):
... print(f_name)
上面的代码查找 some_directory/ 中的所有文件,对其进行迭代,并使用 .endswith() 打印出具有 .txt 文件扩展名的文件名。在我的计算机上运行此代码会产生以下输出:
data_01.txt
data_03.txt
data_03_backup.txt
data_02_backup.txt
data_02.txt
data_01_backup.txt
使用 fnmatch 进行简单文件名模式匹配
字符串方法的匹配能力有限。fnmatch 具有更高级的函数和方法用于模式匹配。我们将考虑 fnmatch.fnmatch(),这是一个支持使用通配符(如 * 和 ?)匹配文件名的函数。例如,要使用 fnmatch 查找目录中的所有 .txt 文件,你可以执行以下操作:
>>> import os
>>> import fnmatch
>>> for file_name in os.listdir('some_directory/'):
... if fnmatch.fnmatch(file_name, '*.txt'):
... print(file_name)
这会迭代 some_directory 中的文件列表,并使用 .fnmatch() 执行通配符搜索以查找具有 .txt 扩展名的文件。
更高级的模式匹配
假设你希望查找符合某些条件的 .txt 文件。例如,你可能只对查找文件名中包含单词 data、一组下划线之间的数字以及单词 backup 的 .txt 文件感兴趣。类似于 data_01_backup、data_02_backup 或 data_03_backup。
使用 fnmatch.fnmatch(),你可以这样做:
>>> for filename in os.listdir('.'):
... if fnmatch.fnmatch(filename, 'data_*_backup.txt'):
... print(filename)
这里,你只打印匹配 data_*_backup.txt 模式的文件名。模式中的星号将匹配任何字符,因此运行此代码将找到所有文件名以单词 data 开头并以 backup.txt 结尾的文本文件,如下所示:
data_03_backup.txt
data_02_backup.txt
data_01_backup.txt
使用 glob 进行文件名模式匹配
另一个有用的模式匹配模块是 glob。glob 模块中的 .glob() 功能与 fnmatch.fnmatch() 相同,但与 fnmatch.fnmatch() 不同的是,它将开头带句点(.)的文件视为特殊文件。
UNIX 及相关系统会将带有通配符(如 ? 和 *)的名称模式转换为文件列表。这称为 globbing。
例如,在 UNIX shell 中键入 mv *.py python_files/ 会将(mv)当前目录中所有 .py 扩展名的文件移动到 python_files 目录。* 字符是通配符,表示“任意数量的字符”,而 *.py 是 glob 模式。这种 shell 功能在 Windows 操作系统中不可用。glob 模块在 Python 中添加了此功能,使 Windows 程序能够使用此特性。
以下是如何使用 glob 搜索当前目录中所有 Python(.py)源文件的示例:
>>> import glob
>>> glob.glob('*.py')
['admin.py', 'tests.py']
glob.glob('*.py') 搜索当前目录中所有具有 .py 扩展名的文件并将其作为列表返回。glob 还支持 shell 风格的通配符来匹配模式:
>>> import glob
>>> for name in glob.glob('*[0-9]*.txt'):
... print(name)
这会查找文件名中包含数字的所有文本(.txt)文件:
data_01.txt
data_03.txt
data_03_backup.txt
data_02_backup.txt
data_02.txt
data_01_backup.txt
glob 还可以轻松地递归搜索子目录中的文件:
>>> import glob
>>> for file in glob.iglob('**/*.py', recursive=True):
... print(file)
此示例使用 glob.iglob() 在当前目录和子目录中搜索 .py 文件。将 recursive=True 作为参数传递给 .iglob() 使其在当前目录及任何子目录中搜索 .py 文件。glob.iglob() 与 glob.glob() 的区别在于 .iglob() 返回一个迭代器而不是列表。
运行上述程序会产生以下输出:
admin.py
tests.py
sub_dir/file1.py
sub_dir/file2.py
pathlib 包含类似的方法用于制作灵活的文件列表。以下示例展示了如何使用 .Path.glob() 列出文件扩展名以字母 p 开头的文件类型:
>>> from pathlib import Path
>>> p = Path('.')
>>> for name in p.glob('*.p*'):
... print(name)
admin.py
scraper.py
docs.pdf
调用 p.glob('*.p*') 返回一个生成器对象,该对象指向当前目录中文件扩展名以字母 p 开头的所有文件。
Path.glob() 与上面讨论的 os.glob() 类似。如你所见,pathlib 将 os、os.path 和 glob 模块的许多最佳功能整合到一个模块中,使其使用起来非常愉快。
总结一下,以下是本节涵盖的函数表:
| 函数 | 描述 |
|---|---|
startswith() |
测试字符串是否以指定模式开头,并返回 True 或 False |
endswith() |
测试字符串是否以指定模式结尾,并返回 True 或 False |
fnmatch.fnmatch(filename, pattern) |
测试文件名是否匹配模式,并返回 True 或 False |
glob.glob() |
返回匹配模式的文件名列表 |
pathlib.Path.glob() |
在路径名中查找模式并返回生成器对象 |
遍历目录和处理文件
一个常见的编程任务是遍历目录树并处理树中的文件。让我们探讨如何使用内置的 Python 函数 os.walk() 来完成此操作。os.walk() 用于通过自上而下或自下而上遍历目录树来生成目录树中的文件名。在本节中,我们将操作以下目录树:
.
├── folder_1/
│ ├── file1.py
│ ├── file2.py
│ └── file3.py
├── folder_2/
│ ├── file4.py
│ ├── file5.py
│ └── file6.py
├── test1.txt
└── test2.txt
以下示例展示了如何使用 os.walk() 列出目录树中的所有文件和目录。os.walk() 默认以自上而下的方式遍历目录:
# 遍历目录树并打印目录和文件的名称
for dirpath, dirnames, files in os.walk('.'):
print(f'Found directory: {dirpath}')
for file_name in files:
print(file_name)
os.walk() 在每次循环迭代时返回三个值:
- 当前文件夹的名称
- 当前文件夹中的文件夹列表
- 当前文件夹中的文件列表
在每次迭代中,它会打印出找到的子目录和文件的名称:
Found directory: .
test1.txt
test2.txt
Found directory: ./folder_1
file1.py
file3.py
file2.py
Found directory: ./folder_2
file4.py
file5.py
file6.py
要以自下而上的方式遍历目录树,请向 os.walk() 传递 topdown=False 关键字参数:
for dirpath, dirnames, files in os.walk('.', topdown=False):
print(f'Found directory: {dirpath}')
for file_name in files:
print(file_name)
传递 topdown=False 参数会使 os.walk() 首先打印子目录中找到的文件:
Found directory: ./folder_1
file1.py
file3.py
file2.py
Found directory: ./folder_2
file4.py
file5.py
file6.py
Found directory: .
test1.txt
test2.txt
如你所见,程序首先列出了子目录的内容,然后列出了根目录的内容。这在需要递归删除文件和目录的情况下非常有用。你将在下面的章节中学习如何做到这一点。默认情况下,os.walk 不会遍历解析为目录的符号链接。通过使用 followlinks=True 参数调用它可以覆盖此行为。
创建临时文件和目录
Python 提供了一个方便的模块用于创建临时文件和目录,称为 tempfile。tempfile 可用于在程序运行时在文件或目录中临时打开和存储数据。当程序完成使用临时文件后,tempfile 会处理其删除。
以下是创建临时文件的方法:
from tempfile import TemporaryFile
# 创建临时文件并向其中写入一些数据
fp = TemporaryFile('w+t')
fp.write('Hello universe!')
# 回到开头并从文件中读取数据
fp.seek(0)
data = fp.read()
# 关闭文件,之后它将被删除
fp.close()
第一步是从 tempfile 模块导入 TemporaryFile。接下来,通过调用 TemporaryFile() 方法并传入要打开文件的模式来创建一个类似文件的对象。这将创建并打开一个可用作临时存储区域的文件。
在上面的示例中,模式为 'w+t',这使得 tempfile 以写入模式创建一个临时文本文件。由于文件在脚本运行结束后会被销毁,因此无需为临时文件指定文件名。
写入文件后,你可以从中读取并在处理完成后关闭它。一旦文件关闭,它将从文件系统中删除。如果你需要为使用 tempfile 生成的临时文件命名,请使用 tempfile.NamedTemporaryFile()。
使用 tempfile 创建的临时文件和目录存储在用于存储临时文件的特殊系统目录中。Python 会在标准目录列表中搜索用户可以创建文件的目录。
在 Windows 上,目录按顺序为 C:\TEMP、C:\TMP、\TEMP 和 \TMP。在所有其他平台上,目录按顺序为 /tmp、/var/tmp 和 /usr/tmp。作为最后的手段,tempfile 会将临时文件和目录保存在当前目录中。
TemporaryFile() 也是一个上下文管理器,因此可以与 with 语句结合使用。使用上下文管理器会在读取文件后自动处理关闭和删除文件:
with TemporaryFile('w+t') as fp:
fp.write('Hello universe!')
fp.seek(0)
fp.read()
# 文件现已关闭并被删除
这将创建一个临时文件并从中读取数据。一旦读取文件内容,临时文件将自动关闭并从文件系统中删除。
tempfile 也可用于创建临时目录。让我们看看如何使用 tempfile.TemporaryDirectory() 做到这一点:
>>> import tempfile
>>> with tempfile.TemporaryDirectory() as tmpdir:
... print('Created temporary directory ', tmpdir)
... os.path.exists(tmpdir)
...
Created temporary directory /tmp/tmpoxbkrm6c
True
>>> # 目录内容已被删除
>>> tmpdir
'/tmp/tmpoxbkrm6c'
>>> os.path.exists(tmpdir)
False
调用 tempfile.TemporaryDirectory() 会在文件系统中创建一个临时目录并返回一个表示该目录的对象。在上面的示例中,目录是使用上下文管理器创建的,临时目录的名称存储在 tmpdir 中。第三行打印出临时目录的名称,os.path.exists(tmpdir) 确认目录是否确实在文件系统中创建。
上下文管理器超出上下文后,临时目录将被删除,对 os.path.exists(tmpdir) 的调用返回 False,这意味着目录已成功删除。
删除文件和目录
你可以使用 os、shutil 和 pathlib 模块中的方法删除单个文件、目录和整个目录树。以下各节描述了如何删除不再需要的文件和目录。
在 Python 中删除文件
要删除单个文件,请使用 pathlib.Path.unlink()、os.remove() 或 os.unlink()。
os.remove() 和 os.unlink() 在语义上是相同的。要使用 os.remove() 删除文件,请执行以下操作:
import os
data_file = 'C:\\Users\\vuyisile\\Desktop\\Test\\data.txt'
os.remove(data_file)
使用 os.unlink() 删除文件与使用 os.remove() 类似:
import os
data_file = 'C:\\Users\\vuyisile\\Desktop\\Test\\data.txt'
os.unlink(data_file)
在文件上调用 .unlink() 或 .remove() 会从文件系统中删除该文件。如果传递给它们的路径指向目录而非文件,这两个函数将抛出 OSError。为避免这种情况,你可以先检查要删除的内容是否确实是文件,仅在是文件时才删除它;或者你可以使用异常处理来处理 OSError:
import os
data_file = 'home/data.txt'
# 如果文件存在,则删除它
if os.path.isfile(data_file):
os.remove(data_file)
else:
print(f'Error: {data_file} not a valid filename')
os.path.isfile() 检查 data_file 是否确实是文件。如果是,则通过调用 os.remove() 将其删除。如果 data_file 指向文件夹,则会向控制台打印错误消息。
以下示例展示了如何使用异常处理来处理删除文件时的错误:
import os
data_file = 'home/data.txt'
# 使用异常处理
try:
os.remove(data_file)
except OSError as e:
print(f'Error: {data_file} : {e.strerror}')
上面的代码首先尝试删除文件,然后再检查其类型。如果 data_file 不是实际的文件,则在 except 子句中处理抛出的 OSError,并向控制台打印错误消息。打印出的错误消息使用 Python f-strings 格式化。
最后,你也可以使用 pathlib.Path.unlink() 删除文件:
from pathlib import Path
data_file = Path('home/data.txt')
try:
data_file.unlink()
except IsADirectoryError as e:
print(f'Error: {data_file} : {e.strerror}')
这会创建一个名为 data_file 的 Path 对象,该对象指向一个文件。在 data_file 上调用 .unlink() 将删除 home/data.txt。如果 data_file 指向的是目录,则会引发 IsADirectoryError。值得注意的是,上述 Python 程序具有与运行它的用户相同的权限。如果用户没有删除该文件的权限,则会引发 PermissionError。
删除目录
标准库提供了以下用于删除目录的函数:
os.rmdir()pathlib.Path.rmdir()shutil.rmtree()
要删除单个目录或文件夹,请使用 os.rmdir() 或 pathlib.rmdir()。这两个函数仅在你要删除的目录为空时才有效。如果目录不为空,则会引发 OSError。以下是删除文件夹的方法:
import os
trash_dir = 'my_documents/bad_dir'
try:
os.rmdir(trash_dir)
except OSError as e:
print(f'Error: {trash_dir} : {e.strerror}')
在这里,通过将路径传递给 os.rmdir() 来删除 trash_dir 目录。如果目录不为空,则会向屏幕打印一条错误消息:
Traceback (most recent call last):
File '<stdin>', line 1, in <module>
OSError: [Errno 39] Directory not empty: 'my_documents/bad_dir'
或者,你可以使用 pathlib 删除目录:
from pathlib import Path
trash_dir = Path('my_documents/bad_dir')
try:
trash_dir.rmdir()
except OSError as e:
print(f'Error: {trash_dir} : {e.strerror}')
在这里,你创建了一个指向要删除目录的 Path 对象。在 Path 对象上调用 .rmdir() 会在目录为空时将其删除。
删除整个目录树
要删除非空目录和整个目录树,Python 提供了 shutil.rmtree():
import shutil
trash_dir = 'my_documents/bad_dir'
try:
shutil.rmtree(trash_dir)
except OSError as e:
print(f'Error: {trash_dir} : {e.strerror}')
当对 trash_dir 调用 shutil.rmtree() 时,其中的所有内容都会被删除。在某些情况下,你可能希望递归地删除空文件夹。你可以结合使用上述方法之一与 os.walk() 来实现这一点:
import os
for dirpath, dirnames, files in os.walk('.', topdown=False):
try:
os.rmdir(dirpath)
except OSError as ex:
pass
此代码会向下遍历目录树,并尝试删除找到的每个目录。如果目录不为空,则会引发 OSError 并跳过该目录。下表列出了本节涵盖的函数:
| 函数 | 描述 |
|---|---|
os.remove() |
删除文件,不能删除目录 |
os.unlink() |
与 os.remove() 相同,删除单个文件 |
pathlib.Path.unlink() |
删除文件,不能删除目录 |
os.rmdir() |
删除空目录 |
pathlib.Path.rmdir() |
删除空目录 |
shutil.rmtree() |
删除整个目录树,可用于删除非空目录 |
复制、移动和重命名文件与目录
Python 自带 shutil 模块。shutil 是 shell utilities(shell 工具)的缩写。它提供了一些高级文件操作,支持复制、归档以及删除文件和目录。在本节中,你将学习如何移动和复制文件与目录。
在 Python 中复制文件
shutil 提供了几个用于复制文件的函数。最常用的函数是 shutil.copy() 和 shutil.copy2()。要使用 shutil.copy() 将文件从一个位置复制到另一个位置,请执行以下操作:
import shutil
src = 'path/to/file.txt'
dst = 'path/to/dest_dir'
shutil.copy(src, dst)
shutil.copy() 类似于基于 UNIX 系统中的 cp 命令。shutil.copy(src, dst) 会将文件 src 复制到 dst 指定的位置。如果 dst 是一个文件,则该文件的内容将被 src 的内容替换。如果 dst 是一个目录,则 src 将被复制到该目录中。shutil.copy() 仅复制文件的内容和文件的权限。其他元数据(如文件的创建时间和修改时间)不会被保留。
要保留复制时的所有文件元数据,请使用 shutil.copy2():
import shutil
src = 'path/to/file.txt'
dst = 'path/to/dest_dir'
shutil.copy2(src, dst)
使用 .copy2() 可以保留有关文件的详细信息,例如最后访问时间、权限位、最后修改时间和标志。
复制目录
虽然 shutil.copy() 仅复制单个文件,但 shutil.copytree() 会复制整个目录及其包含的所有内容。shutil.copytree(src, dest) 接受两个参数:源目录和目标目录(文件和文件夹将被复制到该目录)。
以下是将一个文件夹的内容复制到不同位置的示例:
>>> import shutil
>>> shutil.copytree('data_1', 'data1_backup')
'data1_backup'
在此示例中,.copytree() 将 data_1 的内容复制到新位置 data1_backup,并返回目标目录。目标目录必须不存在。它以及缺失的父目录都将被创建。shutil.copytree() 是备份文件的好方法。
移动文件和目录
要将文件或目录移动到另一个位置,请使用 shutil.move(src, dst)。
src 是要移动的文件或目录,dst 是目标位置:
>>> import shutil
>>> shutil.move('dir_1/', 'backup/')
'backup'
如果 backup/ 存在,shutil.move('dir_1/', 'backup/') 会将 dir_1/ 移动到 backup/ 中。如果 backup/ 不存在,则 dir_1/ 将被重命名为 backup。
重命名文件和目录
Python 包含 os.rename(src, dst) 用于重命名文件和目录:
>>> os.rename('first.zip', 'first_01.zip')
上面的行将 first.zip 重命名为 first_01.zip。如果目标路径指向一个目录,则会引发 OSError。
重命名文件或目录的另一种方法是使用 pathlib 模块中的 rename():
>>> from pathlib import Path
>>> data_file = Path('data_01.txt')
>>> data_file.rename('data.txt')
要使用 pathlib 重命名文件,首先创建一个包含要替换文件路径的 pathlib.Path() 对象。下一步是在路径对象上调用 rename(),并为要重命名的文件或目录传递一个新文件名。
归档
归档是一种将多个文件打包成一个文件的便捷方式。两种最常见的归档类型是 ZIP 和 TAR。你编写的 Python 程序可以创建、读取和从归档中提取数据。在本节中,你将学习如何读取和写入这两种归档格式。
读取 ZIP 文件
zipfile 模块是一个低级模块,属于 Python 标准库的一部分。zipfile 提供了易于打开和提取 ZIP 文件的函数。要读取 ZIP 文件的内容,首先要创建一个 ZipFile 对象。ZipFile 对象类似于使用 open() 创建的文件对象。ZipFile 也是一个上下文管理器,因此支持 with 语句:
import zipfile
with zipfile.ZipFile('data.zip', 'r') as zipobj:
在这里,你创建了一个 ZipFile 对象,并传入要以读取模式打开的 ZIP 文件的名称。打开 ZIP 文件后,可以通过 zipfile 模块提供的函数访问有关归档的信息。上面示例中的 data.zip 归档是从一个名为 data 的目录创建的,该目录总共包含 5 个文件和 1 个子目录:
.
|
├── sub_dir/
| ├── bar.py
| └── foo.py
|
├── file1.py
├── file2.py
└── file3.py
要获取归档中文件的列表,请在 ZipFile 对象上调用 namelist():
import zipfile
with zipfile.ZipFile('data.zip', 'r') as zipobj:
zipobj.namelist()
这会产生一个列表:
['file1.py', 'file2.py', 'file3.py', 'sub_dir/', 'sub_dir/bar.py', 'sub_dir/foo.py']
.namelist() 返回归档中文件和目录的名称列表。要检索归档中文件的信息,请使用 .getinfo():
import zipfile
with zipfile.ZipFile('data.zip', 'r') as zipobj:
bar_info = zipobj.getinfo('sub_dir/bar.py')
bar_info.file_size
这是输出:
15277
.getinfo() 返回一个 ZipInfo 对象,该对象存储有关归档中单个成员的信息。要获取归档中文件的信息,你将文件的路径作为参数传递给 .getinfo()。使用 getinfo(),你可以检索有关归档成员的信息,例如文件上次修改的日期、压缩后的大小和完整文件名。访问 .file_size 可以检索文件的原始大小(以字节为单位)。
以下示例展示了如何在 Python REPL 中检索有关归档文件的更多详细信息。假设已导入 zipfile 模块,并且 bar_info 是你在前面示例中创建的相同对象:
>>> bar_info.date_time
(2018, 10, 7, 23, 30, 10)
>>> bar_info.compress_size
2856
>>> bar_info.filename
'sub_dir/bar.py'
bar_info 包含有关 bar.py 的详细信息,例如其压缩后的大小和完整路径。
第一行展示了如何检索文件的最后修改日期。下一行展示了如何获取文件压缩后的大小。最后一行展示了归档中 bar.py 的完整路径。
ZipFile 支持上下文管理器协议,这就是为什么你可以将其与 with 语句一起使用。这样做会在你完成操作后自动关闭 ZipFile 对象。尝试从已关闭的 ZipFile 对象打开或提取文件将导致错误。
提取 ZIP 归档
zipfile 模块允许你通过 .extract() 和 .extractall() 从 ZIP 归档中提取一个或多个文件。
这些方法默认将文件提取到当前目录。它们都接受一个可选的 path 参数,允许你指定不同的目录来提取文件。如果该目录不存在,则会自动创建。要从归档中提取文件,请执行以下操作:
>>> import zipfile
>>> import os
>>> os.listdir('.')
['data.zip']
>>> data_zip = zipfile.ZipFile('data.zip', 'r')
>>> # 将单个文件提取到当前目录
>>> data_zip.extract('file1.py')
'/home/terra/test/dir1/zip_extract/file1.py'
>>> os.listdir('.')
['file1.py', 'data.zip']
>>> # 将所有文件提取到不同的目录
>>> data_zip.extractall(path='extract_dir/')
>>> os.listdir('.')
['file1.py', 'extract_dir', 'data.zip']
>>> os.listdir('extract_dir')
['file1.py', 'file3.py', 'file2.py', 'sub_dir']
>>> data_zip.close()
第三行代码是对 os.listdir() 的调用,显示当前目录只有一个文件 data.zip。
接下来,你以读取模式打开 data.zip 并调用 .extract() 从中提取 file1.py。.extract() 返回提取文件的完整文件路径。由于未指定路径,.extract() 将 file1.py 提取到当前目录。
下一行打印目录列表,显示当前目录现在除了原始归档外还包括提取的文件。再下一行展示了如何将整个归档提取到 zip_extract 目录。.extractall() 创建 extract_dir 并将 data.zip 的内容提取到其中。最后一行关闭 ZIP 归档。
从密码保护的归档中提取数据
zipfile 支持提取密码保护的 ZIP 文件。要提取密码保护的 ZIP 文件,请将密码作为参数传递给 .extract() 或 .extractall() 方法:
>>> import zipfile
>>> with zipfile.ZipFile('secret.zip', 'r') as pwd_zip:
... # 从密码保护的归档中提取
... pwd_zip.extractall(path='extract_dir', pwd='Quish3@o')
这将以读取模式打开 secret.zip 归档。向 .extractall() 提供密码,并将归档内容提取到 extract_dir。由于使用了 with 语句,在提取完成后归档会自动关闭。
创建新的 ZIP 归档
要创建一个新的 ZIP 归档,你需要以写入模式(w)打开一个 ZipFile 对象,并添加要归档的文件:
>>> import zipfile
>>> file_list = ['file1.py', 'sub_dir/', 'sub_dir/bar.py', 'sub_dir/foo.py']
>>> with zipfile.ZipFile('new.zip', 'w') as new_zip:
... for name in file_list:
... new_zip.write(name)
在该示例中,new_zip 以写入模式打开,并将 file_list 中的每个文件添加到归档中。当 with 语句套件完成后,new_zip 将被关闭。以写入模式打开 ZIP 文件会擦除归档的内容并创建一个新的归档。
要向现有归档添加文件,请以追加模式打开 ZipFile 对象,然后添加文件:
>>> # 以追加模式打开 ZipFile 对象
>>> with zipfile.ZipFile('new.zip', 'a') as new_zip:
... new_zip.write('data.txt')
... new_zip.write('latin.txt')
在这里,你以追加模式打开了上一个示例中创建的 new.zip 归档。以追加模式打开 ZipFile 对象允许你在不删除当前内容的情况下向 ZIP 文件添加新文件。向 ZIP 文件添加文件后,with 语句退出上下文并关闭 ZIP 文件。
打开 TAR 归档
TAR 文件是像 ZIP 一样的未压缩文件归档。它们可以使用 gzip、bzip2 和 lzma 压缩方法进行压缩。TarFile 类允许读取和写入 TAR 归档。
要从归档中读取,请执行以下操作:
import tarfile
with tarfile.open('example.tar', 'r') as tar_file:
print(tar_file.getnames())
tarfile 对象像大多数类文件对象一样打开。它们有一个 open() 函数,该函数接受一个模式,用于确定如何打开文件。
使用 'r'、'w' 或 'a' 模式分别以读取、写入和追加模式打开未压缩的 TAR 文件。要打开压缩的 TAR 文件,请向 tarfile.open() 传递一个形式为 filemode[:compression] 的模式参数。下表列出了 TAR 文件可以打开的可能模式:
| 模式 | 操作 |
|---|---|
r |
以透明压缩方式打开归档进行读取 |
r:gz |
以 gzip 压缩方式打开归档进行读取 |
r:bz2 |
以 bzip2 压缩方式打开归档进行读取 |
r:xz |
以 lzma 压缩方式打开归档进行读取 |
w |
以未压缩方式打开归档进行写入 |
w:gz |
以 gzip 压缩方式打开归档进行写入 |
w:xz |
以 lzma 压缩方式打开归档进行写入 |
a |
以无压缩方式打开归档进行追加 |
.open() 默认为 'r' 模式。要读取未压缩的 TAR 文件并检索其中的文件名,请使用 .getnames():
>>> import tarfile
>>> tar = tarfile.open('example.tar', mode='r')
>>> tar.getnames()
['CONTRIBUTING.rst', 'README.md', 'app.py']
这会返回一个包含归档内容名称的列表。
注意:为了向你展示如何使用不同的
tarfile对象方法,示例中的 TAR 文件在交互式 REPL 会话中手动打开和关闭。以这种方式与 TAR 文件交互可以让你看到运行每个命令的输出。通常,你会希望使用上下文管理器来打开类文件对象。
可以使用特殊属性访问归档中每个条目的元数据:
>>> for entry in tar.getmembers():
... print(entry.name)
... print(' Modified:', time.ctime(entry.mtime))
... print(' Size :', entry.size, 'bytes')
... print()
CONTRIBUTING.rst
Modified: Sat Nov 1 09:09:51 2018
Size : 402 bytes
README.md
Modified: Sat Nov 3 07:29:40 2018
Size : 5426 bytes
app.py
Modified: Sat Nov 3 07:29:13 2018
Size : 6218 bytes
在此示例中,你遍历 .getmembers() 返回的文件列表,并打印出每个文件的属性。.getmembers() 返回的对象具有可以以编程方式访问的属性,例如归档中每个文件的名称、大小和最后修改时间。读取或写入归档后,必须关闭它以释放系统资源。
从 TAR 归档中提取文件
在本节中,你将学习如何使用以下方法从 TAR 归档中提取文件:
.extract().extractfile().extractall()
要从 TAR 归档中提取单个文件,请使用 extract(),并传入文件名:
>>> tar.extract('README.md')
>>> os.listdir('.')
['README.md', 'example.tar']
README.md 文件从归档中提取到文件系统。调用 os.listdir() 确认 README.md 文件已成功提取到当前目录。要解包或提取归档中的所有内容,请使用 .extractall():
>>> tar.extractall(path="extracted/")
.extractall() 有一个可选的 path 参数,用于指定提取文件的目标位置。在这里,归档被解包到 extracted 目录。以下命令显示归档已成功提取:
$ ls
example.tar extracted README.md
$ tree
.
├── example.tar
├── extracted
| ├── app.py
| ├── CONTRIBUTING.rst
| └── README.md
└── README.md
1 directory, 5 files
$ ls extracted/
app.py CONTRIBUTING.rst README.md
要提取一个用于读取或写入的文件对象,请使用 .extractfile(),它接受一个文件名或 TarInfo 对象作为要提取的参数。.extractfile() 返回一个可以读取和使用的类文件对象:
>>> f = tar.extractfile('app.py')
>>> f.read()
>>> tar.close()
打开的归档在读取或写入后应始终关闭。要关闭归档,请在归档文件句柄上调用 .close(),或在创建 tarfile 对象时使用 with 语句,以便在完成后自动关闭归档。这会释放系统资源并将你对归档所做的任何更改写入文件系统。
创建新的 TAR 归档
方法如下:
>>> import tarfile
>>> file_list = ['app.py', 'config.py', 'CONTRIBUTORS.md', 'tests.py']
>>> with tarfile.open('packages.tar', mode='w') as tar:
... for file in file_list:
... tar.add(file)
>>> # 读取新创建的归档的内容
>>> with tarfile.open('package.tar', mode='r') as t:
... for member in t.getmembers():
... print(member.name)
app.py
config.py
CONTRIBUTORS.md
tests.py
首先,你创建一个要添加到归档的文件列表,这样就不必手动添加每个文件。
下一行使用 with 上下文管理器以写入模式打开一个名为 packages.tar 的新归档。以写入模式('w')打开归档使你能够向归档中写入新文件。归档中的任何现有文件都会被删除,并创建一个新的归档。
归档创建并填充后,with 上下文管理器会自动关闭它并将其保存到文件系统。最后三行打开你刚刚创建的归档,并打印出其中包含的文件名。
要向现有归档添加新文件,请以追加模式('a')打开归档:
>>> with tarfile.open('package.tar', mode='a') as tar:
... tar.add('foo.bar')
>>> with tarfile.open('package.tar', mode='r') as tar:
... for member in tar.getmembers():
... print(member.name)
app.py
config.py
CONTRIBUTORS.md
tests.py
foo.bar
以追加模式打开归档允许你在不删除已有文件的情况下向其中添加新文件。
处理压缩归档
tarfile 还可以读取和写入使用 gzip、bzip2 和 lzma 压缩的 TAR 归档。要读取或写入压缩归档,请使用 tarfile.open(),并传入适用于压缩类型的相应模式。
例如,要读取或写入使用 gzip 压缩的 TAR 归档,请分别使用 'r:gz' 或 'w:gz' 模式:
>>> files = ['app.py', 'config.py', 'tests.py']
>>> with tarfile.open('packages.tar.gz', mode='w:gz') as tar:
... tar.add('app.py')
... tar.add('config.py')
... tar.add('tests.py')
>>> with tarfile.open('packages.tar.gz', mode='r:gz') as t:
... for member in t.getmembers():
... print(member.name)
app.py
config.py
tests.py
'w:gz' 模式以 gzip 压缩写入方式打开归档,而 'r:gz' 模式以 gzip 压缩读取方式打开归档。无法以追加模式打开压缩归档。要向压缩归档添加文件,你必须创建一个新的归档。
创建归档的更简单方法
Python 标准库还支持使用 shutil 模块中的高级方法创建 TAR 和 ZIP 归档。shutil 中的归档工具允许你创建、读取和提取 ZIP 和 TAR 归档。这些工具依赖于底层的 tarfile 和 zipfile 模块。
使用 shutil.make_archive() 处理归档
shutil.make_archive() 至少接受两个参数:归档的名称和归档格式。
默认情况下,它会将当前目录中的所有文件压缩为 format 参数中指定的归档格式。你可以传入一个可选的 root_dir 参数来压缩不同目录中的文件。.make_archive() 支持 zip、tar、bztar 和 gztar 归档格式。
以下是使用 shutil 创建 TAR 归档的方法:
import shutil
# shutil.make_archive(base_name, format, root_dir)
shutil.make_archive('data/backup', 'tar', 'data/')
这会复制 data/ 中的所有内容,并在文件系统中创建一个名为 backup.tar 的归档,并返回其名称。要提取归档,请调用 .unpack_archive():
shutil.unpack_archive('backup.tar', 'extract_dir/')
调用 .unpack_archive() 并传入归档名称和目标目录,会将 backup.tar 的内容提取到 extract_dir/。ZIP 归档也可以用同样的方式创建和提取。
读取多个文件
Python 通过 fileinput 模块支持从多个输入流或文件列表中读取数据。该模块允许你快速轻松地循环遍历一个或多个文本文件的内容。以下是 fileinput 的典型用法:
import fileinput
for line in fileinput.input()
process(line)
fileinput 默认从传递给 sys.argv 的命令行参数获取输入。
使用 fileinput 循环遍历多个文件
让我们使用 fileinput 构建一个粗略版本的常见 UNIX 工具 cat。cat 工具按顺序读取文件,并将它们写入标准输出。当在命令行参数中给出多个文件时,cat 会连接文本文件并在终端中显示结果:
# 文件: fileinput-example.py
import fileinput
import sys
files = fileinput.input()
for line in files:
if fileinput.isfirstline():
print(f'\n--- Reading {fileinput.filename()} ---')
print(' -> ' + line, end='')
print()
在我当前目录中的两个文本文件上运行此程序会产生以下输出:
$ python3 fileinput-example.py bacon.txt cupcake.txt
--- Reading bacon.txt ---
-> Spicy jalapeno bacon ipsum dolor amet in in aute est qui enim aliquip,
-> irure cillum drumstick elit.
-> Doner jowl shank ea exercitation landjaeger incididunt ut porchetta.
-> Tenderloin bacon aliquip cupidatat chicken chuck quis anim et swine.
-> Tri-tip doner kevin cillum ham veniam cow hamburger.
-> Turkey pork loin cupidatat filet mignon capicola brisket cupim ad in.
-> Ball tip dolor do magna laboris nisi pancetta nostrud doner.
--- Reading cupcake.txt ---
-> Cupcake ipsum dolor sit amet candy I love cheesecake fruitcake.
-> Topping muffin cotton candy.
-> Gummies macaroon jujubes jelly beans marzipan.
fileinput 允许你检索有关每行的更多信息,例如它是否是第一行(.isfirstline())、行号(.lineno())和文件名(.filename())。你可以在此处阅读更多相关信息。
结论
你现在知道如何使用 Python 对文件和文件组执行最常见的操作。你已经学习了用于读取、查找和操作它们的不同内置模块。
你现在能够使用 Python:
- 获取目录内容和文件属性
- 创建目录和目录树
- 在文件名中查找模式
- 创建临时文件和目录
- 移动、重命名、复制和删除文件或目录
- 从不同类型的归档中读取和提取数据
- 使用
fileinput同时读取多个文件