Python中文件处理
Python 有几个内置的模块和函数来处理文件。这些功能分布在几个模块上,例如os,os``os.path
,shutil
和pathlib
,仅举几例。本文在一个地方收集了许多您需要了解的函数,以便对 Python 中的文件执行最常见的操作。
open
使用Python读取和写入数据非常简单。为此,必须首先在适当的模式下打开文件。下面是如何使用 Python 的“with open(...)作为...”打开文本文件并读取其内容的模式:
with open('data.txt', 'r') as f:
data = f.read()
在上面的示例中,open()
打开文件进行读取或写入,并返回一个文件句柄(在本例中为 f
),该句柄提供可用于读取或写入文件数据的方法。有关如何读取和写入文件的更多信息,请查看在 Python 中读取和写入文件和在 Python 中使用文件 I/O。
获取目录列表
内置os
模块具有许多有用的功能,可用于列出目录内容和过滤结果。要获取文件系统中特定目录中所有文件和文件夹的列表,请在 Python 的旧版本中使用 os.listdir() 或 Python 3.x 中的 os.listdir()``os.scandir()
os.scandir()
旧版Python版本中的目录列表
在 Python 3 之前的 Python 版本中,os.listdir()
是用于获取目录列表的方法:
>>> import os
>>> entries = os.listdir('my_directory/')
os.listdir()
返回一个 Python 列表,其中包含 path 参数给出的目录中的文件和子目录的名称:
>>> os.listdir('my_directory/')
['sub_dir_c', 'file1.py', 'sub_dir_b', 'file3.txt', 'file2.csv', 'sub_dir']
现代Python版本中的目录列表
在现代版本的 Python 中,os.listdir() 的替代方案是使用 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
语句结合使用,因为它支持上下文管理器协议。使用上下文管理器关闭迭代器,并在迭代器用尽后自动释放获取的资源。结果是 my_directory/
中文件名的打印出来,就像您在 os.listdir()
示例中看到的那样:
获取目录列表的另一种方法是使用 pathlib
模块:
from pathlib import Path
entries = Path('my_directory/')
for entry in entries.iterdir():
print(entry.name)
Path 返回的对象是 PosixPath
或 Path
对象,具体取决于WindowsPath
操作系统。
pathlib.Path()
对象有一个 .iterdir()
方法,用于创建目录中所有文件和文件夹的迭代器。.iterdir()
生成的每个条目都包含有关文件或目录的信息,例如其名称和文件属性。pathlib
最初是在 Python 3.4 中引入的,它是 Python 的一个很好的补充,它为文件系统提供了一个面向对象的接口。
在上面的示例中,您调用 pathlib.Path()
并向其传递一个路径参数。接下来是调用 .iterdir()
以获取my_directory
中所有文件和目录的列表.
pathlib
提供了一组类,以简单、面向对象的方式对路径进行了大多数常见操作。使用 pathlib
的效率更高,如果不是同样有效的,如果不是同样有效的,也是在 os
。在os
上使用 pathlib
的另一个好处是,它减少了操作文件系统路径所需的导入次数。有关更多信息,请阅读 Python 3 的 pathlib 模块:驯服文件系统.
注意:要开始使用 pathlib
,请查看 Python 基础知识:文件系统操作和相关练习.
使用pathlib.Path()
或 os.scandir() 而不是 os.listdir()
是获取目录列表的首选方法,尤其是在处理需要文件类型和文件属性信息的代码时。os.listdir()``pathlib.Path()
提供了 os
和 shutil
中的许多文件和路径处理功能,它的方法比这些模块中的一些方法更有效。我们将很快讨论如何获取文件属性。
列出目录中的所有文件
本节将向您展示如何使用 os.listdir()``os.scandir()
和 pathlib.Path()
要过滤掉目录并仅列出由 os.listdir()
生成的目录列表中的文件,请使用 os.path
:
import os
# List all files in a directory using 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()
过滤以仅打印出文件而不是目录。
列出目录中文件的一种更简单的方法是使用 os.scandir()
或 pathlib.Path()
:
import os
# List all files in a directory using 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
。
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)
from pathlib import Path
# List all files in directory using 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)
列出子目录
#方法1
import os
# List all subdirectories using os.listdir
basepath = 'my_directory/'
for entry in os.listdir(basepath):
if os.path.isdir(os.path.join(basepath, entry)):
print(entry)
#方法2
import os
# List all subdirectories using scandir()
basepath = 'my_directory/'
with os.scandir(basepath) as entries:
for entry in entries:
if entry.is_dir():
print(entry.name)
#方法3
from pathlib import Path
# List all subdirectory using pathlib
basepath = Path('my_directory/')
for entry in basepath.iterdir():
if entry.is_dir():
print(entry.name)
获取文件属性
Python 使检索文件大小和修改时间等文件属性变得容易。这是通过 os.stat()、os.scandir()
或 os.stat()``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
创建目录
功能 | 描述 |
---|---|
os.mkdir() |
创建单个子目录 |
pathlib.Path.mkdir() |
创建单个或多个目录 |
os.makedirs() |
创建多个目录,包括中间目录 |
os.makedirs()
类似于 os.mkdir()
两者之间的区别在于,os.makedirs()
不仅可以创建单独的目录,还可以用于创建目录树。换句话说,它可以创建任何必要的中间文件夹,以确保存在完整路径。
.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
文件名模式匹配
使用上述方法之一获取目录中的文件列表后,您很可能希望搜索与特定模式匹配的文件。
以下是您可以使用的方法和功能:
endswith()
) 和startswith()
字符串方法fnmatch.fnmatch()
glob.glob()
pathlib.Path.glob()
使用字符串方法
Python 有几个内置的方法来修改和操作字符串。其中两个方法,.startswith()
) 和 .endswith()
,在文件名中搜索模式时很有用。为此,首先获取目录列表,然后迭代它:
>>> import os
>>> # Get .txt files
>>> for f_name in os.listdir('some_directory'):
... if f_name.endswith('.txt'):
... print(f_name)
使用fnmatch的简单文件名匹配模式
字符串方法的匹配能力受到限制。fnmatch
具有更高级的模式匹配功能和方法。我们将考虑 fnmatch.fnmatchfnmatch.fnmatch()
一个支持使用 *
和 ?
等通配符来匹配文件名的函数。例如,要使用 fnmatch
查找目录中的所有.txt
文件,您需要执行以下操作:
>>> import os
>>> import fnmatch
>>> for file_name in os.listdir('some_directory/'):
... if fnmatch.fnmatch(file_name, '*.txt'):
... print(file_name)
更高级的模式匹配
假设您要查找满足特定条件.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)
使用 glob
的文件名模式匹配
另一个有用的模式匹配模块是 glob
.
glob` 模块中的 .glob() 的工作方式与 fnmatch.fnmatch() 类似,但与 fnmatch.fnmatch() 不同的是,它将以句点`.``.glob()` `fnmatch.fnmatch()` 开头的文件视为特殊文件。`fnmatch.fnmatch()
UNIX 和相关系统将带有通配符(如 ?
和 *
)的名称模式转换为文件列表。这称为通配。
例如,在 UNIX 外壳中键入 mv mv *.py python_files/
会将 (mv
) 所有扩展名为 .py
的文件从当前目录移动到目录python_files
。* *
字符是通配符,表示“任意数量的字符”,*.py
是 glob 模式。此外壳功能在 Windows 操作系统中不可用。glob
模块在 Python 中添加了此功能,使 Windows 程序能够使用此功能。
下面是如何使用 glob
搜索当前目录中所有 Python (.py
) 源文件的示例:
>>> import glob
>>> glob.glob('*.py')
['admin.py', 'tests.py']
#查找文件名中包含数字的所有文本 (.txt) 文件:
>>> import glob
>>> for name in glob.glob('*[0-9]*.txt'):
... print(name)
# glob 也可以轻松地在子目录中递归搜索文件:
>>> import glob
>>> for file in glob.iglob('**/*.py', recursive=True):
... print(file)
glob.glob('*.py')
搜索当前目录中具有.py
扩展名的所有文件,并将它们作为列表返回。glob
还支持 shell 样式的通配符来匹配模式:
此示例使用 glob.iglob()
在当前目录和子目录中搜索.py
文件。将recursive=True
作为参数传递给 .iglob()
会使其搜索当前目录和任何子目录中.py
文件。glob.iglob()
) 和 glob.glob() 之间的区别在于 .iglob()
返回迭代器而不是列表。
遍历目录和处理文件
一个常见的编程任务是遍历目录树并处理树中的文件。让我们探讨如何使用内置的 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()
默认以自上而下的方式遍历目录:
# Walking a directory tree and printing the names of the directories and files
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
要以自下而上的方式遍历目录树,请将 topdown=False
关键字参数传递给 os.walk()
:
for dirpath, dirnames, files in os.walk('.', topdown=False):
print(f'Found directory: {dirpath}')
for file_name in files:
print(file_name)
"""
Found directory: ./folder_1
file1.py
file3.py
file2.py
Found directory: ./folder_2
file4.py
file5.py
file6.py
Found directory: .
test1.txt
"""
创建临时文件和目录
Python 提供了一个方便的模块,用于创建临时文件和目录,称为tempfile
.
tempfile
可用于在程序运行时在文件或目录中临时打开和存储数据。临时文件处理程序处理完临时文件后删除tempfile
的过程。
以下是创建临时文件的方法
from tempfile import TemporaryFile
# Create a temporary file and write some data to it
fp = TemporaryFile('w+t')
fp.write('Hello universe!')
# Go back to the beginning and read data from file
fp.seek(0)
data = fp.read()
# Close the file, after which it will be removed
fp.close()
第一步是从临时文件模块导入TemporaryFile
。tempfile
接下来,使用 TemporaryFile()
方法创建一个类似对象的文件,方法是调用它并传递要在其中打开文件的模式。这将创建并打开一个可用作临时存储区域的文件。
在上面的示例中,模式为'w+t'
,这使得临时文件在写入模式下创建tempfile
。无需为临时文件指定文件名,因为它将在脚本运行完毕后销毁。
写入文件后,可以从中读取并在处理完文件后关闭它。关闭文件后,将从文件系统中删除该文件。如果需要命名使用临时文件生成的临时文件,请使用tempfile``tempfile.NamedTemporaryFile()
.
使用临时文件创建的临时文件和目录存储在用于存储tempfile
的特殊系统目录中。Python 搜索标准的目录列表,以查找用户可以在其中创建文件的目录。
在 Windows 上,目录依次为 C:`C:\TEMP\TMP、\
\TEMP和
C:\TMP。
\TMP在所有其他平台上,目录依次为 /tmp、/var/tmp 和
/usr/tmp``/tmp。
/var/tmp作为最后的手段,临时文件会将
tempfile`和目录保存在当前目录中。
.TemporaryFile()
也是一个上下文管理器,因此它可以与 with
语句结合使用。使用上下文管理器负责在读取文件后自动关闭和删除文件:
with TemporaryFile('w+t') as fp:
fp.write('Hello universe!')
fp.seek(0)
fp.read()
# File is now closed and removed
这将创建一个临时文件并从中读取数据。读取文件内容后,将关闭临时文件并从文件系统中删除。
临时文件也可用于创建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
>>> # Directory contents have been removed
...
>>> 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()
删除文件的方式os.unlink()
:
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 the file exists, delete it
if os.path.isfile(data_file):
os.remove(data_file)
else:
print(f'Error: {data_file} not a valid filename')
最后,你也可以使用 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
上调用 .remove()
将删除 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}')
在这里,trash_dir
目录通过将路径传递给 os.rmdir()
来删除。如果目录不为空,则会在屏幕上打印一条错误消息:
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}')
当调用 shutil.rmtree()
时,trash_dir
中的所有内容都将被删除。在某些情况下,您可能希望以递归方式删除空文件夹。您可以使用上面讨论的方法之一与 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 实用程序的缩写。它提供了许多对文件的高级操作,以支持文件和目录的复制、存档和删除。在本节中,您将学习如何移动和复制文件和目录。
在 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'
重命名文件和目录
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
,请先创建一个 pathlib.Path()
要替换的文件的路径的 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'
ZipFile
支持上下文管理器协议,这就是为什么您可以将其与with
语句一起使用的原因。执行此操作会在完成ZipFile
对象后自动关闭该对象。尝试从关闭的ZipFile
对象中打开或提取文件将导致错误。
提取压缩文档
zipfile
模块允许您通过 .extract() 和 .extractall()
从 ZIP 存档.extract()
中提取一个或多个文件.
默认情况下,这些方法将文件提取到当前目录。它们都采用可选的 path
参数,该参数允许您指定要将文件提取到的不同目录。如果该目录不存在,则会自动创建该目录。要从存档中提取文件,请执行以下操作:
>>> import zipfile
>>> import os
>>> os.listdir('.')
['data.zip']
>>> data_zip = zipfile.ZipFile('data.zip', 'r')
>>> # Extract a single file to current directory
>>> data_zip.extract('file1.py')
'/home/terra/test/dir1/zip_extract/file1.py'
>>> os.listdir('.')
['file1.py', 'data.zip']
>>> # Extract all files into a different directory
>>> 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:
... # Extract from a password protected archive
... 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
对象,然后添加文件:
>>> # Open a ZipFile object in append mode
>>> 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 文件,请将 mode 参数传递给 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
的目录中。以下命令显示已成功提取存档:
要提取文件对象以进行读取或写入,请使用 .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)
>>> # Read the contents of the newly created archive
>>> 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'
模式'r: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'
压缩写入的存档,'r:gz'
压缩读取的存档。无法在追加模式下打开压缩的存档。要将文件添加到压缩存档,必须创建新存档。
创建存档的更简单方法
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/')
读取多个文件
Python 支持通过 fileinput
模块从多个输入流或文件列表中读取数据。此模块允许您快速轻松地循环访问一个或多个文本文件的内容。以下是fileinput
的典型方式:
import fileinput
for line in fileinput.input()
process(line)
fileinput
从传递给 sys.argv
的命令行参数获取其输入。
使用文件输入循环访问多个fileinput
让我们使用 fileinput
来构建一个普通 UNIX cat
的粗略版本。cat
实用程序按顺序读取文件,将它们写入标准输出。当在其命令行参数中给定多个文件时,cat
将连接文本文件并在终端中显示结果:
# File: 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()
)。您可以在此处阅读更多相关信息.