1.7 写入文本文件

迄今为止,大多数示例还是使用print语句将输出发送到命令行窗口或终端窗口。当你在调试程序,或者在检查输出的准确度时,将输出打印到屏幕上是有意义的。但是,在很多情况下,只要你能确定输出是正确的,就会需要将输出写入文件,以进行更进一步的分析、报告和存储。

Python提供了两种简单的方法来将输出写入文本文件和分隔符文件。write方法可将单个字符串写入一个文件,writelines方法可将一系列字符串写入一个文件。下面的两个示例使用range函数和len函数跟踪一个列表中的索引值,以将分隔符放在各个列表值之间,并在最后一个列表值后面放上一个换行符。

1.7.1 向first_script.py添加代码

(1)将下面各行代码添加到first_script.py的底部:

# 写入文件
# 写入一个文本文件
my_letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
max_index = len(my_letters)
output_file = sys.argv[1]
filewriter = open(output_file, 'w')
for index_value in range(len(my_letters)):
    if index_value < (max_index-1):
        filewriter.write(my_letters[index_value]+'\t')
    else:
        filewriter.write(my_letters[index_value]+'\n')
filewriter.close()
print "Output #146: Output written to file"

在这个例子中,变量my_letters是一个字符串列表。这里想把这些字母打印到一个文本文件中,每个字母之间用制表符分隔。这个示例中的难点是确保在字母之间以制表符分隔,并在最后一个字母后面放上一个换行符(不是制表符)。

为了知道什么时候到达最后一个字母,你需要跟踪列表中字母的索引值。len函数用来计算出列表中字母的数量,所以max_index等于10。在命令行窗口或终端窗口中,再次使用sys.argv[1]来在命令行中提供输出文件的路径名。创建一个文件对象filewriter,但是打开方式不是只读,而是通过w(可写)的方式打开。使用for循环在列表my_letters的各个值之间进行迭代,并使用range函数和len函数跟踪列表中各个字母的索引值。

if-else语句可以使你对列表中的最后一个字母做出与前面那些字母不同的处理。if-else语句是这样工作的:my_letters包含10个元素,但是索引从0开始,所以各个字母的索引值分别是0、1、2、3、4、5、6、7、8、9。因此,my_letters[0]是a,my_letters[9]是j。if代码块判断索引值x是否小于9,max_index - 1或者是10 - 1 = 9。直到列表中的最后一个字母,这个条件才为True。因此,if代码块的意义是:一直到列表中的最后一个字母,都向输出文件中写入字母,并在字母后面加一个制表符。当你到达了列表中的最后一个字母时,这个字母的索引值为9,不大于9,所以if代码块判断为False,就执行else代码块。else代码块中的write语句的意义是:向输出文件中写入最后一个字母,并在后面加一个换行符。

(2)将前面读取多个文件的代码注释掉。

为了看到这些代码是如何工作的,这里需要写入一个文件然后查看输出。因为你又一次使用了argv[1]来确定输出文件的路径名,所以需要将前面的glob代码删除或注释掉,这样就可以使用argv[1]来确定输出文件了。如果选择注释掉前面的glob代码,那么first_script.py应该如下所示:

## 读取多个文本文件
#print("Output #145:")
#inputPath = sys.argv[1]
#for input_file in glob.glob(os.path.join(inputPath,'*.txt')):
#    with open(input_file, 'r', newline='') as #filereader:
#        for row in filereader:
#            print("{}".format(row.strip()))

(3)重新保存first_script.py。

(4)要写入一个文本文件,输入下面的代码,如图1-16所示,然后按回车键:

python first_script.py "C:\Users\[Your Name]\Desktop\write_to_file.txt"

图1-16:应该在命令行窗口中输入的Python脚本、文件路径和输出文件名

(5)打开输出文件write_to_file.txt。

这样,你就使用Python将输出写入了一个文本文件。在完成这些步骤之后,你不会在屏幕上看到新的输出;但是,如果你将所有打开的窗口最小化,就会看到桌面上有一个新的文本文件,名为write_to_file.txt。这个文件中应该包含了列表my_letters中的字母,以制表符隔开,最后有一个换行符,如图1-17所示。

图1-17:输出文件write_to_file.txt,由first_script.py在桌面上创建

下一个示例与这个很相似,只是它演示了如何使用str函数来将元素转换为字符串,以便使用write函数将其写入一个文件。它还演示了使用'a'(追加)方式将输出追加到一个已经存在的输出文件末尾的方法。

1.7.2 写入CSV文件

(1)将下列各行代码添加到first_script.py的底部:

# 写入CSV文件
my_numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
max_index = len(my_numbers)
output_file = sys.argv[1]
filewriter = open(output_file, 'a')
for index_value in range(len(my_numbers)):
    if index_value < (max_index-1):
        filewriter.write(str(my_numbers[index_value])+',')
    else:
        filewriter.write(str(my_numbers[index_value])+'\n')
filewriter.close()
print "Output #147: Output appended to file"

这个示例与前面的示例非常相似,但是它说明了如何向已经存在的输出文件中追加内容,以及如何将列表中的非字符串数据转换成字符串,以便可以使用write函数来写入文件。在这个示例中,列表中的元素是整数。write函数处理的是字符串,所以在你使用write函数将其写入输出文件之前,需要使用str函数将非字符串数据转换成字符串。

在使用for循环进行第一次迭代时,str函数会向输出文件中写入一个0,然后写入一个逗号。以这种方式继续写入列表中的其他数值,直到列表中的最后一个数值,这时执行else代码块,将最后一个数值写入输出文件,并在后面加上一个换行符,而不是逗号。

请注意在打开文件对象filewriter时,使用的是追加模式('a'),而不是可写模式('w')。如果在命令行中提供了同样的输出文件名,那么这段代码的输出会被追加到write_to_file.txt文件中,在以前写入文件的内容之后。相反,如果使用可写方式打开filewriter对象,那么以前的输出会被删除,write_to_file.txt文件中只会出现这段代码的输出。你会在本书后面的章节中看到使用追加方式打开文件的作用,这时你要处理多个文件,并将其中所有的数据追加到一个连接文件中。

(2)重新保存first_script.py。

(3)要向文本文件中追加数据,输入以下命令然后按回车键:

python first_script.py "C:\Users\[Your Name]\Desktop\write_to_file.txt"

(4)打开输出文件write_to_file.txt。

这样,你就使用Python向文本文件中写入和追加了数据。在完成这些步骤之后,你不会在屏幕上看到新的输出;但是,如果你打开了write_to_file.txt文件,会看到文件中出现了新的一行,行中包括了my_numbers中的数值,以逗号隔开,并在末尾有一个换行符,如图1-18所示。

图1-18:桌面上的输出文件write_to_file.txt,由first_script.py追加了信息

最后,这个示例演示了一个写入CSV文件的有效方法。实际上,在前面的例子中,你将由制表符分隔的数据写入了输出文件,如果将制表符改为逗号,并且将输出文件命名为write_to_file.csv而不是write_to_file.txt的话,就可以创建一个CSV文件。