文件
让程序能够与更大的外部世界交互:文件和流。
打开文件
可使用函数 open ,它位于自动导入的模块 io 中。
函数 open 将文件名作为唯一必不可少的参数,并返回一个文件对象。 如:
>>> f = open('somefile.txt')
这种调用函数 open 的方式并不能满足通过写入文本来创建文件需求。
文件模式
调用函数 open 时,如果只指定文件名,将获得一个可读取的文件对象。如果要写入文件,必须通过指定模式来显式地指出这一点。
- 显式地指定读取模式的效果与根本不指定模式相同。
- 写入模式让你能够写入文件,并在文件不存在时创建它。
- 独占写入模式更进一步,在文件已存在时引发 FileExistsError 异常。
- ‘+’ 可与其他任何模式结合起来使用,表示既可读取也可写入。
‘r+’ 和 ‘w+’ 之间有个重要差别:后者截断文件,而前者不会这样做。
默认模式为 ‘rt’ ,这意味着将把文件视为经过编码的Unicode文本,因此将自动执行解码和编码,且默认使用UTF-8编码。
默认情况下,行以 ‘\n’ 结尾。 读取时将自动替换其他行尾字符( ‘\r’ 或 ‘\r\n’ );写入时将 ‘\n’ 替换为系统的默认行尾字符( os.linesep )。
通常,Python使用通用换行模式。 如果要使用这种模式,同时禁止自动转换,可将关键字参数 newline 设置为空字符串,如 open(name, newline=’’) 。 如果要指定只将 ‘\r’ 或 ‘\r\n’ 视为合法的行尾字符,可将参数 newline 设置为相应的行尾字符。
如果文件包含非文本的二进制数据,如声音剪辑片段或图像,只需使用二进制模式(如 ‘rb’ )来禁用与文本相关的功能。
文件的基本方法
类似于文件的对象支持文件对象的一些方法,如支持 read 或 write ,或者两者都支持。
urlopen 返回的对象就是典型的类似于文件的对象,它们支持方法 read 和 readline ,但不支持方法 write 和 isatty 。
读取和写入
文件最重要的功能是提供和接收数据。
在文本和二进制模式下,基本上分别将 str 和 bytes 类用作数据。
当调用 f.write(string) 时,提供的字符串都将写入到文件中既有内容的后面。
>>> f = open('somefile.txt', 'w')
>>> f.write('Hello, ')
7
>>> f.write('World!')
6
>>> f.close()
读取也一样简单,只需告诉流要读取多少个字符(在二进制模式下是多少字节),如下所示:
>>> f = open('somefile.txt', 'r')
>>> f.read(4)
'Hell'
>>> f.read()
'o, World!'
注意,调用 open 时,可以不指定模式,因为其默认值就是 ‘r’ 。
使用管道重定向输出
在 bash 等shell中,可依次输入多个命令,并使用管道将它们链接起来。
$ cat somefile.txt | python somescript.py | sort
这条管道线包含三个命令。
- cat somefile.txt : 将文件somefile.txt的内容写入到标准输出( sys.stdout )。
- python somescript.py : 执行Python脚本 somescript 。这个脚本从其标准输入中读取,并将结果写入到标准输出。
- sort : 读取标准输入( sys.stdin )中的所有文本,将各行按字母顺序排序,并将结果写入到标准输出。
管道字符( | )。 管道将一个命令的标准输出链接到下一个命令的标准输入。
读取和写入行
方法 readline :读取一行(从当前位置到下一个分行符的文本)。 也可提供一个非负整数,指定 readline 最多可读取多少个字符。
方法 readlines :读取文件中的所有行,并以列表的方式返回它们 。
方法 writelines :接受一个字符串列表(实际上,可以是任何序列或可迭代对象),并将这些字符串都写入到文件(或流)中。 注意,写入时不会添加换行符,必须自行添加。
没有方法 writeline ,因为可以使用 write 。
关闭文件
调用方法 close 将文件关闭。
通常,程序退出时将自动关闭文件对象(也可能在退出程序前这样做)。
对于写入过的文件,一定要将其关闭,因为Python可能缓冲写入的数据(将数据暂时存储在某个地方,以提高效率)。 因此如果程序因某种原因崩溃,数据可能根本不会写入到文件中。
如果要重置缓冲,让所做的修改反映到磁盘文件中,但又不想关闭文件,可使用方法 flush 。 flush出于锁定考虑而禁止其他正在运行的程序访问这个文件。
要确保文件得以关闭,可使用一条 try / finally 语句,并在 finally 子句中调用 close 。
try:
finally:
file.close()
with 语句。
with open("somefile.txt") as somefile:
do_something(somefile)
with 语句能够打开文件并将其赋给一个变量(这里是 somefile )。 在语句体中,将数据写入文件(还可能做其他事情)。到达该语句末尾时,将自动关闭文件,即便出现异常亦如此。
with 语句实际上是一个非常通用的结构,允许你使用所谓的 上下文管理器。
上下文管理器是支持两个方法的对象: __enter__ 和 __exit__ 。
方法 __enter__ 不接受任何参数,在进入 with 语句时被调用,其返回值被赋给关键字 as 后面的变量。
方法 __exit__ 接受三个参数:异常类型、异常对象和异常跟踪。它在离开方法时被调用(通过前述参数将引发的异常提供给它)。
文件也可用作上下文管理器。它们的方法 __enter__ 返回文件对象本身,而方法 __exit__关闭文件。
使用文件的基本方法
一个简单的文本文件
Welcome to this file
There is nothing here except
This stupid haiku
首先是 read(n) 。
>>> f = open(r'C:\text\somefile.txt')
>>> f.read(7)
'Welcome'
>>> f.read(4)
' to '
>>> f.close()
read() :
>>> f = open(r'C:\text\somefile.txt')
>>> print(f.read())
Welcome to this file
There is nothing here except
This stupid haiku
>>> f.close()
readline() :
>>> f = open(r'C:\text\somefile.txt')
>>> for i in range(3):
print(str(i) + ': ' + f.readline(), end='')
0: Welcome to this file
1: There is nothing here except
2: This stupid haiku
>>> f.close()
readlines() :
>>> import pprint
>>> pprint.pprint(open(r'C:\text\somefile.txt').readlines())
['Welcome to this file\n',
'There is nothing here except\n',
'This stupid haiku']
写入,首先是 write(string) 。
>>> f = open(r'C:\text\somefile.txt', 'w')
>>> f.write('this\nis no\nhaiku')
13
>>> f.close()
修改后的文本文件。
this
is no
haiku
writelines(list) :
>>> f = open(r'C:\text\somefile.txt')
>>> lines = f.readlines()
>>> f.close()
>>> lines[1] = "isn't a\n"
>>> f = open(r'C:\text\somefile.txt', 'w')
>>> f.writelines(lines)
>>> f.close()
再次修改后的文本文件。
this
isn't a
haiku
迭代文件内容
一种常见的文件操作是迭代其内容,并在迭代过程中反复采取某种措施。
使用一个名为 process 的虚构函数来表示对每个字符或行所做的处理。
def process(string):
print('Processing:', string)
更有用的实现包括将数据存储在数据结构中、计算总和、使用模块 re 进行模式替换以及添加行号。
另外,要尝试运行这些示例,应将变量 filename 设置为实际使用的文件的名称。
每次一个字符(或字节)
一种最简单(也可能是最不常见)的文件内容迭代方式是,在 while 循环中使用方法 read 。
使用 read 遍历字符。
with open(filename) as f:
char = f.read(1)
while char:
process(char)
char = f.read(1)
到达文件末尾时,方法 read 将返回一个空字符串;在此之前, 返回的字符串都只包含一个字符(对应于布尔值 True )。
以不同的方式编写循环。
with open(filename) as f:
while True:
char = f.read(1)
if not char: break
process(char)
每次一行
处理文本文件时,通常想做的是迭代其中的行,而不是每个字符。
在 while 循环中使用 readline。
with open(filename) as f:
while True:
line = f.readline()
if not line: break
process(line)
方法 readline ,可像迭代字符一样轻松地迭代行。
读取所有内容
可使用方法 read 并不提供任何参数(将整个文件读取到一个字符串中),也可使用方法 readlines (将文件读取到一个字符串列表中,其中每个字符串都是一行)。
使用 read 迭代字符。
with open(filename) as f:
for char in f.read():
process(char)
使用 readlines 迭代行。
with open(filename) as f:
for line in f.readlines():
process(line)
使用 fileinput 实现延迟行迭代
可使用一种名为延迟行迭代的方法——说它延迟是因为它只读取实际需要的文本部分。
注意,模块 fileinput 会负责打开文件,只需给它提供一个文件名即可。
使用 fileinput 迭代行。
import fileinput
for line in fileinput.input(filename):
process(line)
文件迭代器
迭代文件
with open(filename) as f:
for line in f:
process(line)
将文件用作了上下文管理器,以确保文件得以关闭。
在不将文件对象赋给变量的情况下迭代文件。
for line in open(filename):
process(line)
sys.stdin 也是可迭代的。
要迭代标准输入中的所有行,可像下面这样做:
import sys
for line in sys.stdin:
process(line)
另外,可对迭代器做的事情基本上都可对文件做,如(使用 list(open(filename)) )将其转换为字符串列表,其效果与使用 readlines 相同。
>>> f = open('somefile.txt', 'w')
>>> print('First', 'line', file=f)
>>> print('Second', 'line', file=f)
>>> print('Third', 'and final', 'line', file=f)
>>> f.close()
>>> lines = list(open('somefile.txt'))
>>> lines
['First line\n', 'Second line\n', 'Third and final line\n']
>>> first, second, third = open('somefile.txt')
>>> first
'First line\n'
>>> second
'Second line\n'
>>> third
'Third and final line\n'
在这个示例中,需要注意如下几点。
- 使用了 print 来写入文件,这将自动在提供的字符串后面添加换行符。
- 对打开的文件进行序列解包,从而将每行存储到不同的变量中。
- 写入文件后将其关闭,以确保数据得以写入磁盘。
小结
本章介绍的新函数
学习参考资料:
《Python基础教程》 第3版
|