目录| 上一节(1.5 列表) | 下一节 (1.7 函数)

1.6 文件管理

大多数的程序需要从某处读取输入。本节讨论文件访问。

文件输入和输出

打开一个文件:

f = open('foo.txt', 'rt')     # Open for reading (text)
g = open('bar.txt', 'wt') # Open for writing (text)

读取所有的数据:

data = f.read()

# Read only up to 'maxbytes' bytes
data = f.read([maxbytes])

写入一些文本:

g.write('some text')

当你完成操作后,关闭文件:

f.close()
g.close()

文件应该被正确的关闭,这是很容易忘记的一个步骤。因此,首选方法是像下面这样使用 with 语句:

with open(filename, 'rt') as file:
# Use the file `file`
...
# No need to close explicitly
...statements

当控制流离开缩进的代码块时,这将会自动关闭文件。

读取文件数据的习惯用法

以字符串的形式一次性读取整个文件:

with open('foo.txt', 'rt') as file:
data = file.read()
# `data` is a string with all the text in `foo.txt`

通过迭代逐行读取文件:

with open(filename, 'rt') as file:
for line in file:
# Process the line

写入文件的习惯用法

写入字符串数据:

with open('outfile', 'wt') as out:
out.write('Hello World\n')
...

重定向 print() 函数:

with open('outfile', 'wt') as out:
print('Hello World', file=out)
...

练习

本练习依赖于 Data/portfolio.csv 文件。该文件由一行一行的关于股票投资组合的信息构成。假定你是在 practical-python/Work/ 目录下进行操作。如果你不确定自己所在的目录,你可以通过执行以下操作找出 Python 运行的目录:

>>> import os
>>> os.getcwd()
'/Users/beazley/Desktop/practical-python/Work' # Output vary
>>>

练习 1.26: 文件预览

首先,尝试以字符串的形式一次性读取整个文件:

>>> with open('Data/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('Data/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('Data/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() 函数获取数据了。所以,通常情况下,除非你像上面展示的那样试图显式跳过或者读取一行,否则,不要直接调用 next() 函数。

一旦读取文件的各行,你就可以开始执行更多的操作,例如拆分。

示例,尝试以下操作:

>>> f = open('Data/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()

注意:在这些示例中,因为没有使用 with 语句,所以 f.close() 被显式的调用。

练习 1.27: 读取数据文件

现在你已经知道如何读取文件,让我们编写一个程序来执行简单的计算。

portfolio.csv 文件里面的列对应股票的名称,股票的数量以及单支股票持有的购买价格。编写一个名为 pcost.py 的程序来打开这个文件,读取所有的行并且计算在所有的股票投资组合中花费多少钱来购买这些股份。

提示:要将字符串转为整数,使用 int() 函数。要将字符串转为浮点数,使用 float() 函数。

你的程序应该打印如下输出:

Total cost 44671.15

练习 1.28: 其它类型的“文件"

如果你想读取非文本文件(如 gzip 压缩的数据文件)怎么办?虽然内建 open() 函数在这里帮不了你了,但是 Python 提供的 gzip 模块可以读取 gzip 文件。

试试看:

>>> import gzip
>>> with gzip.open('Data/portfolio.csv.gz', 'rt') as f:
for line in f:
print(line, end='') ... look at the output ...
>>>

注意:此处包含 'rt' 文件模式至关重要。如果你忘记使用它,你将会得到字节字符串而不是通常的文本字符串。

说明: 我们不应该为此使用 Pandas 吗?

数据科学家很快指出,诸如 Pandas 这样的库已经具有读取 CSV 文件的函数,为什么不使用 Pandas 呢?的确如此——而且效果也很好。但是,这不是一门有关学习 Pandas 的课程,读取文件是一个比读取 CSV 文件更普遍的问题。我们使用 CSV 文件做例子的主要原因是:它是大多数编码人员熟悉的格式,并且相对易于直接使用——在读取 CSV 文件的过程中,阐明了许多 Python 特性。所以,当你回到工作中,请务必使用 Pandas。但是,在本课程剩下部分,我们将会继续使用标准的 Python 函数。

目录| 上一节(1.5 列表) | 下一节 (1.7 函数)

注:完整翻译见 https://github.com/codists/practical-python-zh

翻译:《实用的Python编程》01_06_Files的更多相关文章

  1. 翻译:《实用的Python编程》InstructorNotes

    实用的 Python 编程--讲师说明 作者:戴维·比兹利(David Beazley) 概述 对于如何使用我的课程"实用的 Python 编程"进行教学的问题,本文档提供一些通用 ...

  2. 翻译:《实用的Python编程》README

    欢迎光临 大约 25 年前,当我第一次学习 Python 时,发现 Python 竟然可以被高效地应用到各种混乱的工作项目上,我立即被震惊了.15 年前,我自己也将这种乐趣教授给别人.教学的结果就是本 ...

  3. 翻译:《实用的Python编程》05_02_Classes_encapsulation

    目录 | 上一节 (5.1 再谈字典) | 下一节 (6 生成器) 5.2 类和封装 创建类时,通常会尝试将类的内部细节进行封装.本节介绍 Python 编程中有关封装的习惯用法(包括私有变量和私有属 ...

  4. 翻译:《实用的Python编程》04_02_Inheritance

    目录 | 上一节 (4.1 类) | 下一节 (4.3 特殊方法) 4.2 继承 继承(inheritance)是编写可扩展程序程序的常用手段.本节对继承的思想(idea)进行探讨. 简介 继承用于特 ...

  5. 翻译:《实用的Python编程》01_02_Hello_world

    目录 | 上一节 (1.1 Python) | 下一节 (1.3 数字) 1.2 第一个程序 本节讨论有关如何创建一个程序.运行解释器和调试的基础知识. 运行 Python Python 程序始终在解 ...

  6. 翻译:《实用的Python编程》03_03_Error_checking

    目录 | 上一节 (3.2 深入函数) | 下一节 (3.4 模块) 3.3 错误检查 虽然前面已经介绍了异常,但本节补充一些有关错误检查和异常处理的其它细节. 程序是如何运行失败的 Python 不 ...

  7. 翻译:《实用的Python编程》03_04_Modules

    目录 | 上一节 (3.3 错误检查) | 下一节 (3.5 主模块) 3.4 模块 本节介绍模块的概念以及如何使用跨多个文件的函数. 模块和导入 任何一个 Python 源文件都是一个模块. # f ...

  8. 翻译:《实用的Python编程》03_05_Main_module

    目录 | 上一节 (3.4 模块) | 下一节 (3.6 设计讨论) 3.5 主模块 本节介绍主程序(主模块)的概念 主函数 在许多编程语言中,存在一个主函数或者主方法的概念. // c / c++ ...

  9. 翻译:《实用的Python编程》04_01_Class

    目录 | 上一节 (3.6 设计讨论) | 下一节 (4.2 继承) 4.1 类 本节介绍 class 语句以及创建新对象的方式. 面向对象编程(OOP) 面向对象编程是一种将代码组织成对象集合的编程 ...

随机推荐

  1. 一文打尽端口复用 VS Haproxy端口复用

    出品|MS08067实验室(www.ms08067.com) 本文作者:Spark(Ms08067内网安全小组成员) 1.概述   Haproxy是一个使用c语言开发的高性能负载均衡代理软件,提供tc ...

  2. PL/SQL 学习分享

    PL SQL概述 什么是PLSQL PLSQL的特点 PLSQL的开发环境 PLSQL的工作原理 语句块重点部分 PLSQL声明命名规则 声明 命名规则 表达式和运算符 表达式的分类 运算符分类 流程 ...

  3. 项目action:前台传多个dataWrap给后台

    业务描述:当前台需要向后台传递多个dataWrap时,需要给后台action加上一段方法,才可以获取到额外的dataWrap. @Override public List<String> ...

  4. IP路由__距离矢量路由选择协议

    矢量路由选择协议 1.距离矢量路由选择算法发送完整的路由选择表到相邻的路由器,然后,相邻的路由器会将接收到的路由表项与自己原有的路由表进行组合,以完善路由器的路由表. 由于路由器接收到的更新只是来自相 ...

  5. mysql高级day2

    Mysql高级-day02 1. Mysql的体系结构概览 整个MySQL Server由以下组成 Connection Pool : 连接池组件 Management Services & ...

  6. [源码分析] Dynomite 分布式存储引擎 之 DynoJedisClient(1)

    [源码分析] Dynomite 分布式存储引擎 之 DynoJedisClient(1) 目录 [源码分析] Dynomite 分布式存储引擎 之 DynoJedisClient(1) 0x00 摘要 ...

  7. AcWing 250 磁力快(分块)

    题目传送门 在一片广袤无垠的原野上,散落着N块磁石. 每个磁石的性质可以用一个五元组(x,y,m,p,r)描述,其中x,y表示其坐标,m是磁石的质量,p是磁力,r是吸引半径. 若磁石A与磁石B的距离不 ...

  8. 1154 Vertex Coloring

    题目前半略 Sample Input: 10 11 8 7 6 8 4 5 8 4 8 1 1 2 1 4 9 8 9 1 1 0 2 4 4 0 1 0 1 4 1 0 1 3 0 0 1 0 1 ...

  9. Educational Codeforces Round 90 (Rated for Div. 2) B. 01 Game(字符串博弈)

    题目链接:https://codeforces.com/contest/1373/problem/B 题意 给出一个二进制串 $s$,Alica 和 Bob 每次可以选择移去 $s$ 中的一个 $10 ...

  10. poj1821——Fence

    题意: 一个栅栏一共有n(从1--n)个木板,我们找k个工人去粉刷它,li表示每个人有限制粉刷木板数量,pi表示粉刷一个木板得到的钱,si表示他开始在那个木板前面 如果一个工人要粉刷,那么他必须粉刷s ...