Python 是一种流行的解释型动态类型编程语言,用于构建 Web 服务、桌面应用程序、自动化脚本和机器学习项目。程序员在使用基于 Python 的软件项目时,通常必须访问操作系统的文件系统。
例如,我们使用文本文件作为输入,编写文本文件作为输出,并经常处理二进制文件。与任何其他流行的通用编程语言一样,Python 也提供跨平台文件处理功能。Python 通过几个内置函数和标准模块提供文件处理功能。
在本文中,我将解释您需要了解的有关 Python 文件处理的所有信息,包括:
在开始本教程之前,请确保已安装 Python 3 解释器。否则,请从官方版本安装最新的 Python 解释器。您也可以在现有的 Python 项目中使用本教程的代码片段。
作为第一个活动,让我们编写一些代码来读取文本文件。我们需要先创建一个文件对象来读取文件。
Python 提供了内置函数来创建具有多种模式的文件对象,例如读取模式、写入模式等。创建一个名为的文本文件并输入以下内容。openmyFile.txt
Programming languages
C
C++
Python
JAVAScript
Go
现在,创建一个名为的新文件并添加以下代码片段。mAIn.py
myFile = open("myFile.txt", "r") # or open("myFile.txt")
print(myFile.read())
myFile.close()
上面的代码片段的第一行使用给定的文件名创建文件对象。内置函数使用读取模式创建文件处理程序,因为我们通过第二个参数提供了标志。myFileopenr
请确保在使用文件后调用该方法以释放资源。该方法返回文件内容,因此在执行上述代码后,您将看到内容,如下所示。closeread
该方法一次读取整个文件。如果不想一次读取所有内容,可以使用方法的参数指定字节大小。例如,以下代码段仅读取前 11 个字节。readread
myFile = open("myFile.txt", "r")
print(myFile.read(11)) # Programming
myFile.close()
您将看到第一个单词(“编程”)作为输出 - 因为第一个单词有 11 个字母,并且字母的大小等于 ASCII 编码中的一个字节。如果再次打印 的结果,您将看到接下来的 11 个字节(“ languagesn”),因为文件光标在上一个方法调用中移动了 11 位。可以使用该方法将文件光标重置回开头,如以下示例所示。read(11)read(11)seek
myFile = open("myFile.txt")
print(myFile.read(11)) # Programming
print(myFile.read(10)) # languages
myFile.seek(0) # Sets file cursor to the beginning
print(myFile.read(11)) # Programming
myFile.close()
在大多数情况下,很容易逐行处理文件内容。你不需要自己实现面向行的文件读取机制——Python 提供了内置的功能来逐行读取文件。您可以使用循环和方法逐行读取文件,如下所示。for-inreadlines
myFile = open("myFile.txt", "r")
for line in myFile.readlines():
print(line)
myFile.close()
可以使用循环获取当前行号,因为该方法将使用列表类型返回行。以下代码片段将打印行内容及其各自的行号。for-enumeratereadlines
myFile = open("myFile.txt", "r")
for i, line in enumerate(myFile.readlines()):
print(i, line) # line number and content
myFile.close()
之前,我们使用标志创建了具有读取模式的文件对象。使用读取模式无法写入文件,因此我们必须使用写入模式()来写入文件。rw
也可以使用 or 标志同时启用读取和写入模式;我们将在下面的示例中使用该标志。r+w+w+
要开始文件编写,让我们通过编写一些 Python 代码将以下文本输入到当前文本。myFile.txt
Programming languages
Rust
Ruby
TypeScript
Dart
Assembly
使用以下脚本更新上述内容。myFile.txt
myFile = open("myFile.txt", "w")
content = """Programming languages
Rust
Ruby
TypeScript
Dart
Assembly"""
myFile.write(content)
myFile.close()
在这里,我们使用 Python 多行字符串语法定义文本文件内容,并使用该方法将内容写入文件。确保将写入模式与标志一起使用 — 否则,写入操作将失败并出现异常。
writewio.UnsupportedOperation
有时,我们经常不得不将新内容附加到现有文件中。在这些情况下,由于资源消耗较高,读取和写入整个内容不是一个好方法。相反,我们可以使用追加模式 ()。a
请看下面的代码。它将向 中的列表中添加新的编程语言。myFile.txt
myFile = open("myFile.txt", "a")
myFile.write("nBash")
myFile.close()
上面的代码片段向现有文件添加了新行字符 () 和一个新单词,而无需写入整个文件内容。结果,我们将在编程语言列表中看到一个新条目。尝试添加更多条目,看看会发生什么!n
除了原始文件内容外,磁盘上的文件还将包含一些元数据或文件属性,其中包括大小、上次修改时间、上次访问时间等。
查看下面的文件代码,其中显示了文件大小、上次访问时间和上次修改时间。
import os, time
stat = os.stat("myFile.txt")
print("Size: %s bytes" % stat.st_size)
print("Last accessed: %s" % time.ctime(stat.st_atime))
print("Last modified: %s" % time.ctime(stat.st_mtime))
该函数返回一个包含许多文件属性详细信息的统计信息结果对象。在这里,我们用于获取文件大小,获取上次访问的文件时间戳,并获取上次修改的时间戳。统计信息结果对象可能因操作系统而异。例如,在 windows 操作系统上,您可以通过密钥检索特定于 Windows 的文件属性。
os.statst_sizeat_atimest_mtimest_file_attributes
如果只需要获取文件大小,则可以使用该方法而不检索所有元数据,如以下代码所示。os.path.getsize
import os, time
size = os.path.getsize("myFile.txt")
print("Size: %s bytes" % size)
Python 提供了创建单个目录的功能。以下代码片段在当前工作目录中创建。os.mkdirmyFolder
import os
os.mkdir("myFolder")
如果您尝试使用上述代码递归创建多个目录,它将失败。例如,您无法一次创建,因为它需要创建多个目录。在这些情况下,该函数将为我们提供帮助,如下所示。myFolder/abcos.makedirs
import os
os.makedirs("myFolder/abc") # Creates both "myFolder" and "abc"
Python 还提供了一个简单的 API 来通过函数列出目录内容。以下代码片段列出了当前工作目录中的所有文件和目录。os.listdir
import os
cur_dir = os.getcwd()
entries = os.listdir(cur_dir)
print("Found %s entries in %s" % (len(entries), cur_dir))
print('-' * 10)
for entry in entries:
print(entry)
执行上述脚本后,它将显示当前目录的条目,如下所示。
尝试从其他目录执行脚本。然后它将显示该特定目录的条目,因为我们使用该函数来获取当前工作目录。os.getcwd
有时我们需要递归列出目录内容。该函数帮助我们处理递归目录列表。以下代码以递归方式列出当前工作目录的所有条目。os.walk
import os
cur_dir = os.getcwd()
for root, sub_dirs, files in os.walk(cur_dir):
rel_root = os.path.relpath(root)
print("Showing entries of %s" % rel_root)
print("-" * 10)
for entry in sub_dirs + files:
print(entry)
该函数在内部具有递归实现。它为每个条目返回三个值:os.walk
在这里,我们分别使用 、 和变量,以及一个 for 循环来捕获所有条目。rootsub_dirsfiles
我们可以使用该函数删除文件。可以之前使用该函数来防止异常。查看以下示例代码片段。
os.removeos.path.existsos.remove
import os
file_to_remove = "myFile.txt"
if os.path.exists(file_to_remove):
os.remove(file_to_remove)
else:
print("%s doesn't exist!" % file_to_remove)
Python 标准库还提供了删除单个目录的功能。它的行为类似于,如果特定目录有一些条目,则不会删除目录。首先,尝试使用以下代码删除单个目录。os.rmdiros.mkdir
import os
dir_to_remove = "myFolder"
if os.path.exists(dir_to_remove):
os.rmdir(dir_to_remove)
else:
print("%s doesn't exist!" % dir_to_remove)
如果包含子文件夹或文件,上面的代码将引发错误。使用以下代码片段以递归方式删除目录。myFolder
import os, shutil
dir_to_remove = "myFolder"
if os.path.exists(dir_to_remove):
shutil.rmtree(dir_to_remove) # Recursively remove all entries
else:
print("%s doesn't exist!" % dir_to_remove)
当我们使用自动化脚本时,有时我们需要在磁盘上执行文件搜索。例如,程序员经常需要通过他们的 Python 脚本查找日志文件、图像文件和各种文本文件。在 Python 中执行文件搜索有几种不同的方法:
总体而言,第三种方法最适合大多数方案,因为它具有内置的过滤支持,非常好的性能,并且需要开发人员端的最少代码(更多Pythonic)。让我们使用 Python glob 模块实现文件搜索。
import glob, os
query = "**/*.py"
entries = glob.glob(query, recursive=True)
no_of_entries = len(entries)
if no_of_entries == 0:
print("No results for query: %s" % query)
else:
print("Found %s result(s) for query: %s" % (no_of_entries, query))
print("-" * 10)
for entry in entries:
print(entry)
上面的代码以递归方式列出了当前目录中的所有 Python 源文件。查询变量中的前两个星号 () 指示 Python 搜索每个子目录,而最后一个星号表示任何文件名。**
运行上述脚本。您将看到 Python 源文件,如下所示。
尝试通过更改变量来搜索不同的文件类型。query
早些时候,我们处理了文本文件。默认情况下,内置函数使用文本模式 () 创建文件对象。非文本文件(如图像文件、zip 文件和视频文件)不能被视为纯文本文件——因为没有可读的英语句子二进制文件。因此,我们必须通过字节级(或位级)处理将二进制文件视为非文本文件。opent
要开始使用二进制文件处理,让我们编写一个包含一些字节的二进制文件。我们将以下字节保存到 .myFile.bin
01010000 01111001 01110100 01101000 01101111 01101110
为简单起见,我们可以分别使用以下十进制值表示上述字节。
80 121 116 104 111 110
现在,将以下代码添加到 Python 源文件并执行它以创建二进制文件。
myBinaryFile = open("myFile.bin", "wb") # wb -> write binary
bytes = bytearray([80, 121, 116, 104, 111, 110])
myBinaryFile.write(bytes)
myBinaryFile.close()
在这里,我们将一个字节数组实例传递给文件对象的方法。另外,请注意,我们使用二进制模式 () 来创建文件对象。执行上述代码片段后,打开使用您喜欢的文本编辑器新创建的代码。您将看到以下结果。writebmyFile.bin
我们收到了“Python”作为输出,因为字节数组的字节表示已知的 ASCII 字符。例如,() 表示 ASCII 编码中的字母。即使我们将可读文本保存在二进制文件中,几乎所有二进制文件都包含不可读的字节流。尝试通过文本编辑器打开图像文件。8001010000P
现在我们可以在以下示例代码中看到二进制文件读取操作。
myBinaryFile = open("myFile.bin", "rb")
bytes = myBinaryFile.read()
print(bytes) # bytearray(b'Python')
print("Bytes: ", list(bytes)) # Bytes: [80, 121, 116, 104, 111, 110]
myBinaryFile.close()
Python 使用二进制模式的方法返回字节。在这里,我们使用构造函数将字节转换为实例。readbytearraybytearray
程序员经常将归档文件与基于 Python 的 Web 应用程序、Web 服务、桌面应用程序和实用程序一起使用,以一次输出或输入多个文件。例如,如果您正在构建基于 Web 的文件管理器,则可以为用户提供一项功能,通过以编程方式生成的 zip 文件一次下载多个文件。
Python 标准库通过该模块提供存档文件处理 API。首先,让我们创建一个包含 内容的存档。请看下面的代码。确保在运行代码片段之前创建并添加一些文件。shutilmyFoldermyFolder
import shutil
output_file = "myArchive"
input_dir = "myFolder"
shutil.make_archive(output_file, "zip", input_dir)
您可以使用以下代码将存档文件提取到其中。myNewFolder
import shutil
input_file = "myArchive.zip"
output_dir = "myNewFolder"
shutil.unpack_archive(input_file, output_dir)
该模块还提供跨平台 API 函数来复制和移动文件。请看以下示例。shutil
import shutil
# copy main.py -> main_copy.py
shutil.copy("main.py", "main_copy.py")
# move (rename) main_copy.py -> main_backup.py
shutil.move("main_copy.py", "main_backup.py")
# recursive copy myFolder -> myFolder_copy
shutil.copytree("myFolder", "myFolder_copy")
# move (rename) myFolder_copy -> myFolder_backup
# if myFolder_backup exists, source is moved inside folder
shutil.move("myFolder_copy", "myFolder_backup")
print("Done.")
程序员遵循各种编码实践。同样,Python 程序员在处理文件时也遵循不同的编码实践。
例如,一些程序员手动使用 try-finally 阻止和关闭文件处理程序。一些程序员通过省略方法调用来让垃圾回收器关闭文件处理程序——这不是一个好的做法。同时,其他程序员使用该语法来处理文件处理程序。closewith
在本节中,我将总结一些在 Python 中处理文件的最佳实践。首先,查看遵循文件处理最佳做法的以下代码。
def print_file_content(filename):
with open(filename) as myFile:
content = myFile.read()
print(content)
file_to_read = "myFile.txt"
try:
print_file_content(file_to_read)
except:
print("Unable to open file %s " % file_to_read)
else:
print("Successfully print %s's content" % file_to_read)
在这里,我们使用关键字隐式关闭文件处理程序。此外,我们使用 try-except 块处理可能的异常。在使用 Python 文件处理时,可以确保代码具有以下几点。with
def process_file(filename):
with open(filename, "w+") as myFile:
# w+: read/write and create if doesn't exist unlike r+
# Write content
myFile.write("Hello Python!")
print("Cursor position: ", myFile.tell()) # 13
# Reset internal buffer
myFile.flush()
# Set cursor to the beginning
myFile.seek(0)
print("Cursor position: ", myFile.tell()) # 0
# Print new content
content = myFile.read()
print(content)
print("Cursor position: ", myFile.tell()) # 13
file_to_read = "myFile.txt"
try:
process_file(file_to_read)
except:
print("Unable to process file %s " % file_to_read)
else:
print("Successfully processed %s" % file_to_read)
以上内容首先将字符串保存到文件中。之后,它通过重置内部缓冲区再次读取新添加的内容。该方法清除内存中临时保存的数据,因此下一次读取将返回新添加的内容。此外,我们需要使用方法调用将光标重置为开头,因为该方法将其设置为结尾。flushseek(0)write
Python为程序员提供了一个简单的语法。因此,几乎所有的文件操作都易于实现。但是,Python 在标准库设计方面存在一些问题,因此同一事物有多个 API 函数。因此,您必须根据您的要求选择最合适的标准模块。
此外,与其他流行的编程语言相比,Python 是一种速度较慢的语言。考虑到这一点,请确保在不使用太多资源的情况下优化 Python 脚本。例如,您可以通过逐行处理大型文本文件来优化性能,而无需一次处理整个内容。
在本教程中,我们讨论了通用文本文件处理和二进制文件处理。如果您需要处理特定的文件格式,选择更好的库或标准模块可能是值得的。例如,您可以使用 csv 标准模块处理 CSV 文件,使用 PyPDF2 库处理 PDF 文件。此外,pickle 标准模块可帮助您使用文件存储(和加载)Python 数据对象。