简介
大多数程序都需要从某处读取输入。本节将讨论文件访问。
大多数程序都需要从某处读取输入。本节将讨论文件访问。
打开一个文件。
f = open('foo.txt', 'rt') ## 以读取模式(文本)打开
g = open('bar.txt', 'wt') ## 以写入模式(文本)打开
读取所有数据。
data = f.read()
## 最多读取'maxbytes' 字节的数据
data = f.read([maxbytes])
写入一些文本。
g.write('some text')
完成后关闭文件。
f.close()
g.close()
文件应该正确关闭,但这很容易被遗忘。因此,推荐的方法是像这样使用 with 语句。
with open(filename, 'rt') as file:
## 使用文件 `file`
...
## 无需显式关闭
...语句
当控制离开缩进的代码块时,这会自动关闭文件。
一次性将整个文件作为字符串读取。
with open('foo.txt', 'rt') as file:
data = file.read()
## `data` 是一个包含 `foo.txt` 中所有文本的字符串
通过迭代逐行读取文件。
with open(filename, 'rt') as file:
for line in file:
## 处理该行
写入字符串数据。
with open('outfile', 'wt') as out:
out.write('Hello World\n')
...
重定向 print 函数。
with open('outfile', 'wt') as out:
print('Hello World', file=out)
...
这些练习依赖于一个名为 portfolio.csv 的文件。该文件包含一系列行,每行都有关于一个股票投资组合的信息。假设你在 ~/project/ 目录下工作。如果你不确定,可以通过以下方式查看 Python 认为它正在运行的位置:
>>> import os
>>> os.getcwd()
'/home/labex/project' ## 输出可能不同
>>>
首先,尝试一次性将整个文件作为一个大字符串读取:
>>> with open('portfolio.csv', 'rt') as f:
data = f.read()
>>> data
'name,shares,price\n"AA",100,32.20\n"IBM",50,91.10\n"CAT",150,83.44\n"MSFT",200,51.23\n"GE",95,40.37\n"MSFT",50,65.10\n"IBM",100,70.44\n'
>>> print(data)
name,shares,price
"AA",100,32.20
"IBM",50,91.10
"CAT",150,83.44
"MSFT",200,51.23
"GE",95,40.37
"MSFT",50,65.10
"IBM",100,70.44
>>>
在上述示例中,需要注意的是 Python 有两种输出模式。在第一种模式下,当你在提示符处输入 data 时,Python 会向你展示原始字符串表示形式,包括引号和转义码。当你输入 print(data) 时,你会得到字符串的实际格式化输出。
虽然一次性读取整个文件很简单,但这通常不是最合适的方法 —— 特别是当文件非常大或者包含你想要一次处理一行的文本行时。
要逐行读取文件,可以使用如下的 for 循环:
>>> with open('portfolio.csv', 'rt') as f:
for line in f:
print(line, end='')
name,shares,price
"AA",100,32.20
"IBM",50,91.10
...
>>>
当你像这样使用这段代码时,行会一直被读取,直到到达文件末尾,此时循环停止。
在某些情况下,你可能想要手动读取或跳过 一行 文本(例如,也许你想要跳过第一行的列标题)。
>>> f = open('portfolio.csv', 'rt')
>>> headers = next(f)
>>> headers
'name,shares,price\n'
>>> for line in f:
print(line, end='')
"AA",100,32.20
"IBM",50,91.10
...
>>> f.close()
>>>
next() 会返回文件中的下一行文本。如果你重复调用它,你会得到连续的行。不过,要知道,for 循环已经在使用 next() 来获取其数据了。因此,通常你不会直接调用它,除非你像这样试图明确地跳过或读取一行。
一旦你开始读取文件的行,你就可以开始进行更多的处理,比如分割。例如,试试这个:
>>> f = open('portfolio.csv', 'rt')
>>> headers = next(f).split(',')
>>> headers
['name','shares', 'price\n']
>>> for line in f:
row = line.split(',')
print(row)
['"AA"', '100', '32.20\n']
['"IBM"', '50', '91.10\n']
...
>>> f.close()
注意:在这些示例中,显式调用了 f.close(),因为没有使用 with 语句。
既然你已经知道如何读取文件了,那我们来编写一个程序进行简单的计算。
portfolio.csv 中的列分别对应股票名称、股票持有数量以及单只股票的购买价格。在 /home/labex/project 目录下编写一个名为 pcost.py 的程序,该程序打开此文件,读取所有行,并计算购买投资组合中所有股票的总成本。
提示:要将字符串转换为整数,使用 int(s)。要将字符串转换为浮点数,使用 float(s)。
你的程序应输出如下内容:
Total cost 44671.15
如果你想读取一个非文本文件,比如一个 gzip 压缩的数据文件,该怎么办呢?内置的 open() 函数在这里帮不了你,但 Python 有一个库模块 gzip,它可以读取 gzip 压缩文件。
试试看:
>>> import gzip
>>> with gzip.open('portfolio.csv.gz', 'rt') as f:
for line in f:
print(line, end='')
... 查看输出结果...
>>>
注意:这里包含 'rt' 文件模式至关重要。如果你忘了这一点,你得到的将是字节串而不是普通的文本字符串。
数据科学家们很快指出,像 Pandas 这样的库已经有读取 CSV 文件的函数。这没错,而且效果相当不错。然而,这不是一门学习 Pandas 的课程。读取文件是一个比 CSV 文件的具体细节更具普遍性的问题。我们使用 CSV 文件的主要原因是,它是大多数程序员熟悉的格式,并且直接处理起来相对容易,在此过程中还能说明许多 Python 特性。所以,回去工作时你当然可以使用 Pandas。不过在本课程的其余部分,我们将坚持使用标准的 Python 功能。
恭喜你!你已经完成了文件管理实验。你可以在 LabEx 中练习更多实验来提升你的技能。