原文: Python Read File – How to Open, Read, and Write to Files in Python

在使用任何编程语言时,读文件和写文件都是常见的操作。你可以编写代码,以便从文件中读取数据或指令,然后也写入数据。这就提高了效率,减少了人工劳动。

Python 有一个明确的方法来打开、读取和写入文件。在 Python 中操作文件的一些应用包括:读取数据以进行算法训练和测试、读取文件以创建生成艺术、报告和读取配置文件。

在本教程中,你将学习:

  • 如何将文件加载到主内存并创建一个 file handle
  • 如何使用 file handle 来打开文件进行阅读和写作
  • 在处理文件时的异常处理

前提条件:

  • 确保你安装了最新的 Python 版本
  • 熟悉你选择的任何支持 Python 的文本编辑器
  • 对基本的 Python 语法有一定的熟悉程度

要快速访问 Python IDE,请查看 Replit。你也可以克隆这个仓库并在 Replit 上运行它。

持久性和如何将文件加载到主内存中

文件是在计算机的二级存储器中。二级存储器是持久性的,这意味着当计算机关闭电源时,数据不会被清除。一旦你对一个文件进行修改并保存,这些修改就会永久写入并保存在二级存储器中。

为了处理文件,我们需要先将它们加载到主存储器中。主存储器是临时缓存存储器,在短暂的时间内保存请求的数据。当计算机断电时,这些数据就会丢失。

Files are loaded from secondary memory to the main memory and then processed by the CPU. Once the processing is done, the data is written back to the secondary memory.
文件从二级存储器加载到主存储器,然后由 CPU 处理。处理完毕后,数据被写回二级存储器

Python 通过 “file handlers(文件处理程序)”与主内存中加载的文件进行交互。让我们详细了解一下 file handler。

file handler 如何工作

当我们想读或写一个文件时,我们必须首先打开它。打开一个文件向操作系统发出信号,根据文件名搜索该文件,并确保其存在。

如果打开成功,操作系统就会返回一个 file handler。然后我们可以通过 file handler 与文件进行交互。

file handler 不包含数据本身,它只是提供一个处理文件操作的接口。

A file handler provides your program access to data in the secondary memory.
file handler 使你的程序可以访问二级存储器中数据

如何打开一个文件

在这个例子中,我们将打开文件 daffodils.txt。注意,这个文件应该和你的 Python 程序存放在同一个文件夹里。你可以从这个 GitHub 链接中下载 daffodils.txt 文件。

请看一下这个文件,因为我们将在接下来的例子中使用它的内容。

例子:

fhand = open('daffodils.txt')
print(fhand)

在上面的例子中,如果打开成功,操作系统将在变量 fhand 中返回 file handle。默认情况下,你只能读取该文件。

输出:

image-177
file handle 的输出

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

异常情况:

如果文件不存在,我们会得到这样的一个异常:

Exception when the file is not found.
当文件不存在时的异常

如何打印文件

现在我们有了 file handle,这意味着我们可以访问该文件。让我们打印该文件,看看它的内容。

例子:

# 获得 file handler
fhand = open('daffodils.txt')

# 通过 file handler 遍历每一行
for line in fhand:
  print(line) 

输出

image-179
打印文件的内容

我们能够成功地访问和打印该文件。但是,你是否注意到,每行之间有额外的空行?这是有原因的。让我们在下一节看看。

如何处理多余的空行

新行字符在 Python 中用 \n 表示。这个字符在字符串的任何地方都会增加一个新行。

在每一行的末尾都有一个新行字符,它将输出打印到下一行。我们可以用 repr 方法将其可视化。

根据 Python 文档repr() 方法返回一个包含一个对象的可打印形式的字符串。这意味着我们可以看到任何出现在字符串中的特殊字符,如 \t\n

让我们运行下面的例子,看看输出结果。

image-180
Representation of strings using repr().
image-3
使用 repr() 的字符串呈现

例子

回到我们的文件,我们可以使用 repr() 来检查特殊字符。

# 获得 file handler
fhand = open('daffodils.txt')

# 通过 file handler 遍历每一行
for line in fhand:
  print(repr(line)) 

输出:

image-181
在这里,我们可以看到幕后发生的事情

此外,print 方法默认会添加一个新行。这意味着使用 print,我们会在输出中得到另一个新行。我们可以用两种方法来处理这个额外的行。

方法 #1:改变 print 的默认结束值

下面的代码片段显示了 print 函数的参数。我们可以看到,默认情况下,end 的值是 /n。这意味着每个打印语句都会以 \n 结束。

image-22
Source: Python documentation.

我们可以把默认值 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")

输出:

image-4
使用 print() 在相同的和不同的行上打印

回到我们的主文件,让我们稍微修改一下代码,以获得没有多余空行的输出。

# 获得 file handler
fhand = open('daffodils.txt')

# 对于 fhand 中的行,遍历每一行并修改 “end” 的默认值
  print(line, end = '')

输出

在这里,我们得到了期望的输出!

image-5
使用 print() 打印,没有多余的行

方法 #2:使用 rstrip() 方法

我们可以使用 strip() 方法去除字符串周围的某些字符。

现在我们知道,默认情况下,文件中的每一行都有 "\n" 在结尾。由于我们只关心右边的字符,所以我们将使用 rstrip(),它代表的是 right-strip。接下来我们将讨论一个 rstrip() 的例子。

你可以在这篇博文中了解更多关于 strip() 方法的信息。

# 获得 file handler
fhand = open('daffodils.txt')

# 对于 fhand 中的行,遍历每一行,并使用 rstrip() 删除多余的行:
for line in fhand:
  line = line.rstrip()
  print(line)

输出:

image-6
使用 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)
要求用户输入一个文件名

输出

Request the user to enter the file name.
要求用户输入文件名

如何在 Python 中写一个文件

默认情况下,file handler 以读模式打开文件。如果我们用以下任何一种模式打开一个文件,我们就可以向该文件写入:

  • w -(Write)写入一个现有的文件,但删除现有内容
  • a -(Append)附加到一个现有的文件
  • x -(Create)创建一个文件,如果文件存在则返回错误

如何向一个文件写入

注意,如果我们试图用 w 标志打开一个已经存在的文件,其内容会被覆盖。

# Open file with mode 'w'
fout = open('flower.txt', 'w')
fout.write("This content would be added and existing would be discarded")
fout.close()

如何追加到一个文件中

a 标志可以追加到现有的内容,并保留现有的内容。

# 用模式 'a' 打开文件
fout = open('flower.txt', 'a')
fout.write("Now the file has more content at the end!")
fout.close()

如何创建一个文件并向其中写入内容

x 模式创建一个文件,并向其中添加内容。

# 用模式 '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'

异常处理

有可能我们请求的文件并不存在,这样就会因为异常而使程序崩溃:

image-189

为了使程序更加友好,我们可以在一个 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)

输出

image-188
使用 try-except 代码块进行异常处理

总结

知道如何处理文件是编程中的一个基本概念。在本教程中,你学到了如何使用 file handler 在 Python 中打开文件进行读写。

为了便于你参考,我在这个 GitHub 仓库中包含了所有的代码片段和示例文件。

我希望你觉得这个教程对你有帮助。

你最喜欢的从这个教程中学到的东西是什么?请在 Twitter 上告诉我!

你也可以在这里阅读我的其他文章。

题图来源: