在使用任何编程语言时,读和写文件都是一种常见的操作。你可以对你的代码进行编程,以便从文件中读取数据或指令,然后也写入数据。这就提高了效率,减少了手工劳动。
Python有一个明确的方法来打开、读取和写入文件。在Python中,文件操作的一些应用包括:读取数据进行算法训练和测试,读取文件创建生成性艺术,报告,以及读取配置文件。
在本教程中,你将学习:
- 如何将文件加载到主内存并创建一个文件句柄
- 如何使用文件句柄来打开文件进行阅读和写作
- 在处理文件时的异常处理
前提条件:
- 确保你安装了最新的Python版本
- 熟悉你选择的任何支持Python的文本编辑器
- 对Python的基本语法有一定的熟悉
要快速访问Python IDE,请查看Replit。你也可以克隆这个 repo 并在 Replit 上运行它。
持久性和如何将文件加载到主内存中
文件驻留在计算机的二级存储器中。二级存储器是持久性的,这意味着当计算机关闭电源时,数据不会被清除。一旦你对一个文件进行修改并保存,这些修改就会永久写入并保存在二级存储器中。
为了处理文件,我们需要先将它们加载到主存储器中。主存储器是临时缓存存储器,在短暂的时间内保存请求的数据。当计算机断电时,这些数据就会丢失:

文件从二级存储器加载到主存储器,然后由CPU处理。一旦处理完毕,数据就被写回二级存储器。
Python 通过"文件处理程序"与主存中加载的文件进行交互。让我们来详细了解一下文件处理程序。
文件处理程序如何工作
当我们想读或写一个文件时,我们必须首先打开 它。打开一个文件向操作系统发出信号,根据文件名搜索该文件,并确保其存在。
如果打开成功,操作系统就会返回一个文件处理程序。然后我们可以通过文件处理程序与我们的文件进行交互。
文件处理程序不包含数据本身,它只是提供一个处理文件操作的接口:

文件处理程序为你的程序提供对二级存储器中数据的访问。
如何打开一个文件
在这个例子中,我们将打开文件daffodils.txt 。注意,这个文件应该和你的Python程序存放在同一个文件夹中。你可以从这个GitHub链接下载该文件daffodils.txt 。
请看一下这个文件,因为我们将在接下来的例子中使用它的内容。
例子:
fhand = open('daffodils.txt')
print(fhand)
在上面的例子中,如果打开成功,操作系统将在变量fhand 中返回文件柄。默认情况下,你只能读取该文件。
输出:

文件句柄的输出。
在输出中,我们收到了一个文件句柄,其中name 是文件名,mode 是权限,在我们的例子中是r (代表read )。encoding 是Unicode字符集的编码机制。你可以在这里了解更多关于UTF-8的细节。
异常情况
如果文件不存在,我们会得到这样的一个异常:

未找到文件时的异常。
如何打印文件
现在我们有了文件句柄,这意味着我们可以访问该文件。让我们打印该文件,看看它的内容。
例子:
# Get the file handler
fhand = open('daffodils.txt')
# Loop through each line via file handler
for line in fhand:
print(line)
输出:

打印一个文件的内容。
我们能够成功地访问和打印该文件。但是,你是否注意到,我们在每一行之间都有额外的空行?这是有原因的。让我们在下一节看看。
如何处理多余的行空格
新行字符在 Python 中用\n 表示。这个字符在字符串的任何地方都会增加一个新行。
在每一行的末尾都有一个新行字符,将输出打印到下一行。我们可以用repr 方法将其可视化。
根据Python文档,repr() 方法返回一个包含对象的可打印表示的字符串。这意味着我们可以看到出现在字符串中的任何特殊字符,如\t or a \n 。
让我们在下面运行一个例子,看看输出结果:

使用repr() 来表示字符串。
例子:
回到我们的文件,我们可以使用repr() 来检查特殊字符。
# Get the file handler
fhand = open('daffodils.txt')
# Loop through each line via file handler
for line in fhand:
print(line)
输出:

在这里我们可以看到幕后发生的事情。
此外,print方法默认会添加一个新行。这意味着使用print,我们会在输出中得到另一个新行。我们可以用两种方法来处理这个额外的行。
方法#1:改变print的默认结束值
下面的片段显示了print 函数的参数。我们可以看到,默认情况下,end 的值是\n 。这意味着每个print语句都会以\n 。

源于此:Python文档。
我们可以把默认值end='\n' 改为空白,这样我们就不会在每一行的末尾得到一个新行。让我们看看下面的例子来更好地理解:
# By default output would go in separate lines
print("Hello")
print("World")
# Print on the same line because end = ' '
# added single space
print("Hello", end = ' ')
print("World")
输出:

使用print() ,在相同和不同的行上打印。
回到我们的主文件,让我们修改一下代码,得到没有多余空行的输出:
# Get the file handler
fhand = open('daffodils.txt')
# Loop through each line and modify the default value of 'end'
for line in fhand:
print(line, end = '')
输出:
在这里我们得到了我们想要的输出!

使用print() ,打印没有多余的行。
方法#2:使用rstrip()方法
我们可以使用strip() 方法删除字符串周围的某些字符。
现在我们知道,在默认情况下,文件中的每一行在结尾都有"\n" 。由于我们只关心右边的字符,所以我们将使用rstrip() ,它代表的是right-strip。接下来我们将讨论一个rstrip() 的例子。
你可以在这篇博文中了解更多关于strip() 的方法:
# Get the file handler
fhand = open('daffodils.txt')
# Loop through each line and remove extra line character with rstrip()
for line in fhand:
line = line.rstrip()
print(line)
输出:

使用rstrip打印没有多余的行() 。
如何让用户选择一个文件
与其硬编码文件名,我们可以通过让用户选择一个文件来使代码变得动态。
让我们要求用户输入一个文件名。然后我们将计算该文件的行数。
例子:
fname = input('Enter the file name: ')
fhand = open(fname)
count = 0
for line in fhand:
count = count + 1
print('There are', count, 'lines in', fname)
要求用户输入一个文件名。
输出:

要求用户输入文件名。
如何在Python中写一个文件
默认情况下,文件处理程序以读模式打开文件。如果我们用以下任何一种模式打开一个文件,我们就可以向该文件写入:
w- (Write) 写入一个现有的文件,但删除现有内容。a- (Append)附加到一个现有的文件。x- (Create)创建一个文件,如果该文件存在则返回错误。
如何写到一个文件
注意,如果我们试图用w 标志打开一个已经存在的文件,其内容会被覆盖:
# Open file with mode 'w'
fout = open('flower.txt', 'x')
fout.write("This content would be added and existing would be discarded")
fout.close()
如何追加到一个文件
a 标志附加到现有的内容上,并保留现有的内容:
# Open file with mode 'a'
fout = open('flower.txt', 'a')
fout.write("Now the file has more content at the end!")
fout.close()
如何创建一个文件并写入它
x 模式创建一个文件并向其中添加内容:
# Open file with mode 'x'
fout = open('new-file.txt', 'x')
fout.write("Now the new file has some content!")
fout.close()
如果该文件存在,我们会得到一个像这样的异常:
Traceback (most recent call last):
File "main.py", line 2, in <module>
fout = open('flower.txt', 'x')
FileExistsError: [Errno 17] File exists: 'flower.txt'
异常处理
有可能我们请求的文件并不存在。这就会因为异常而使程序爆炸:

为了使程序更加友好,我们可以在一个try-except 块中处理这个异常。
程序中预计会被炸毁的风险部分被写在try 块中。在代码执行没有异常的情况下,except 块被跳过,程序继续运行。如果发现有异常,则运行except 块,并通过exit 命令优雅地关闭程序:
fname = input('Enter the file name: ')
try:
fhand = open(fname)
except:
print('File nout found and can not be opened:', fname)
exit()
count=0
for line in fhand:
count = count + 1
print('There are', count, 'lines in', fname)
输出:

使用try-except块处理异常。
总结
知道如何处理文件是编程中的一个基本概念。在本教程中,你学会了如何使用文件处理程序在 Python 中打开文件进行读写。
为了便于参考,我把所有的代码片段和样本文件都包含在这个GitHub repo中。
我希望你觉得这个教程很有帮助。
你最喜欢从本教程中学到的东西是什么?请在Twitter上告诉我。
你也可以在这里阅读我的其他文章。