1.5 读取文本文件

数据几乎无一例外地是被保存在文件中的。这些文件可能是文本文件、CSV文件、Excel文件或其他类型的文件。知道如何访问此类文件以及从中读取数据是在Python中进行数据处理、加工与分析的前提。当完成了一个每秒钟可以处理很多文件的程序时,与手动一个个地处理文件相比,你会真正体会到写程序的好处。

你需要告诉Python,脚本要处理何种类型的文件。你可以在程序中写死文件名称,但是如果这样的话,就不能使用这个程序处理多个不同的文件了。能读取多个不同文件的方法是,在命令行窗口或终端窗口的命令行中,在Python脚本的名字后面加上完整的文件路径名。要使用这种方法,需要在脚本开始时导入内置的sys模块。在脚本上方加上import sys语句之后,就可以在脚本中使用sys模块提供的所有功能了:

#!/usr/bin/env python3
from math import exp, log, sqrt
import re
from datetime import date, time, datetime, timedelta
from operator import itemgetter
import sys

导入了sys模块之后,你就可以使用argv这个列表变量了。这个变量捕获了传递给Python脚本的命令行参数列表,即你在命令行中的所有输入,包括你的脚本名称。和任何其他列表一样,argv也有索引。argv[0]就是脚本名称,argv[1]是命令行中传递给脚本的第一个附加参数,在这个例子中,就是first_script.py将要读取的文件路径名。

1.5.1 创建文本文件

要读取一个文本文件,首先要创建它。要创建文本文件,需执行以下步骤。

(1)打开Spyder IDE或一个文本编辑器(例如:Windows系统下的Notepad、Notepad++、Sublime Text;macOS系统下的TextMate、TextWrangler、Sublime Text)。

(2)在文本文件中写入下面6行(参见图1-10):

I'm
already
much
better
at
Python.

图1-10:Notepad++中的文本文件file_to_read.txt(Windows)

(3)将文件保存在桌面上,文件名为file_to_read.txt。

(4)将下面几行代码添加到first_script.py的下方:

# 读取文件
# 读取单个文本文件
input_file = sys.argv[1]

print "Output #143: "
filereader = open(input_file, 'r')
for row in filereader:
    print row.strip()
filereader.close()

示例中的第一行代码使用sys.argv列表捕获了要读取的文件的路径名,并将路径名赋给变量input_file。第二行代码创建了一个文件对象filereader,其中包含了以r模式(只读模式)打开的input_file文件中的各个行。下一行中的for循环每次读取filereader对象中的一行。for循环内部的print语句打印出每一行,并且在打印之前用strip函数去掉每一行两端的空格、制表符和换行符。最后一行代码在输入文件中的所有行都被读取并打印到屏幕后,关闭filereader对象。

(5)重新保存first_script.py。

(6)要读取刚才创建的文本文件,输入下面的命令,如图1-11所示,然后按回车键:

python first_script.py file_to_read.txt

图1-11:Python脚本和它要在命令行窗口中处理的文本文件

这样,你就在Python中读取了一个文本文件。你会看到下面的内容被打印到屏幕上,在以前的输出之后(图1-12):

I'm
already
much
better
at
Python.

图1-12:first_script.py的输出,在命令行窗口中处理文本文件

1.5.2 脚本和输入文件在同一位置

因为first_script.py和file_to_read.txt在同一位置,即都在桌面上,所以简单地输入python first_script.py file_to_read.txt是可以的。如果文本文件和脚本不在同一位置,就需要输入文本文件的完整路径名,这样脚本才能知道去哪里寻找这个文件。

例如,如果文本文件在你的Documents文件夹中,而不是在桌面上,那么你可以在命令行中使用下面的路径名来从其所处位置读取文本文件:

python first_script.py "C:\Users\[Your Name]\Documents\file_to_read.txt"

1.5.3 读取文件的新型语法

前面讲的用来创建filereader对象的那行代码是创建文件对象的传统方法。这种方法没有什么问题,但是它使文件对象一直处于打开状态,直到使用close函数明确地关闭或直到脚本结束。尽管这种做法一般没有问题,但不够清晰,还被证明在更复杂的脚本中会导致错误。从Python 2.5开始,你可以使用with语句来创建文件对象。这种语法在with语句结束时会自动关闭文件:

input_file = sys.argv[1]
print("Output #144:")
with open(input_file, 'r', newline='') as filereader:
for row in filereader:
    print("{}".format(row.strip()))

你可以看到,使用with语句的版本与前一个版本非常相似,但是它不需调用close函数来关闭filereader对象。

这个示例演示了如何使用sys.argv来访问并打印一个文本文件中的内容。这是一个简单的示例,但在后面的示例中,要以此为基础访问其他类型的文件,或一次访问多个文件,并向输出文件中写入内容。

下一节介绍glob模块,它让你能够通过几行代码读取和处理多个输入文件。glob模块之所以功能强大,是因为它处理的是文件夹(也就是说,它处理目录,不是单个的文件),所以将前面读取文件的代码删除或注释掉,这样就可以使argv[1]指向一个文件夹,而不是一个文件了。将代码注释掉就是在你希望计算机忽略掉的代码前面加上一个井号,所以当你结束注释时,first_script.py文件就应该像下面这样:

## 读取一个文本文件(旧方法) ##
#input_file = sys.argv[1]
#print("Output #143:")
#filereader = open(input_file, 'r', newline='')
#for row in filereader:
# print("{}".format(row.strip()))
#filereader.close()
## 读取一个文本文件(新方法) ##
#input_file = sys.argv[1]
#print("Output #144:")
#with open(input_file, 'r', newline='') as filereader:
# for row in filereader:
# print("{}".format(row.strip()))

做完这些修改之后,你就可以添加下一节要讨论的glob代码来处理多个文件了。