第十一章 文件
11.1 打开文件
要打开文件,可使用函数open,它位于自动导入的模块io中。函数open将文件名作为唯一必不可少的参数,并返回一个文件对象。
from contextlib import contextmanager
import sys,pprint
f=open('xx.txt')
f.close()
文件模式
调用函数open时,如果只指定文件名,将获得一个可读取的文件对象。如果要写入文件,必须通过指定模式来显式地指出这一点。函数open的参数mode的可能取值有多个
'r' 读取模式(默认值)
'w' 写入模式
'x' 独占写入模式
'a' 附加模式
'b' 二进制模式(与其他模式结合使用)
't' 文本模式(默认值,与其他模式结合使用)
'+' 读写模式(与其他模式结合使用)
独占写入模式更进一步,在文件已存在时引发FileExistsError异常。在写入模式下打开文件时,既有内容将被删除(截断),并从文件开头处开始写入;如果要在既有文件末尾继续写入,可使用附加模式。
'+'可与其他任何模式结合起来使用,表示既可读取也可写入。例如,要打开一个文本文件进行读写,可使用'r+'。(你可能还想结合使用seek,详情请参阅本章后面的旁注“随机存取”。)请注意,'r+'和'w+'之间有个重要差别:后者截断文件,而前者不会这样做。
11.2 文件的基本方法
11.2.1 读取和写入
使用 文件对象.write来写入数据,还可使用 文件对象.read来读取数据。
f=open('xx.txt','w')
f.write('你好')
f.write('Python')
f.close()
读取也一样简单:
f=open('xx.txt','r')
w=f.read()
print(w)
f.close()
你好Python
------------------
(program exited with code: 0)
请按任意键继续. . .
如果只想输出几个字符则:
f=open('xx.txt','r')
w=f.read(4)
print(w)
你好Py
------------------
(program exited with code: 0)
请按任意键继续. . .
11.2.2 使用管道重定向输出
使用管道重定向输出需要系统命令 | 。
管道就是标准输出链接到下一个命令的标准输入。
11.2.3 读取和写入行
要读取一行(从当前位置到下一个分行符的文本),可使用方法readline。调用这个方法时,可不提供任何参数(在这种情况下,将读取一行并返回它);也可提供一个非负整数,指定readline最多可读取多少个字符。
f=open('xx.txt','r')
line=f.readline()
print(line)
f.close()
你好Python,你好Python,你好Python,你好Python,你好Python
------------------
(program exited with code: 0)
请按任意键继续. . .
11.2.4 关闭文件
要确保文件得以关闭,可使用一条try/finally语句,并在finally子句中调用close。
f=open('xx.txt')
try:
line=f.readline()
pass
pass
pass
finally:
f.close
实际上,有一条好像专门为此设计的语句,那就是with语句。
with open('xx.txt','r+') as f:
f.writelines('别忘了调用方法close将文件关闭。')
line=f.readlines()
print(line)
['你好Python,你好Python,你好Python,你好Python,你好Python\n', '你好sys,你好sys,你
好sys,你好sys,你好sys,你好sys,你好sys.\n', '别忘了调用方法close将文件关闭。']
------------------
(program exited with code: 0)
请按任意键继续. . .
___上下文管理器
with语句实际上是一个非常通用的结构,允许你使用所谓的上下文管理器。上下文管理器是支持两个方法的对象:__enter__和__exit__。
方法__enter__不接受任何参数,在进入with语句时被调用,其返回值被赋给关键字as后面的变量。
方法__exit__接受三个参数:异常类型、异常对象和异常跟踪。它在离开方法时被调用(通过前述参数将引发的异常提供给它)。如果__exit__返回False,将抑制所有的异常。
可以自定义上下文管理器。因为with语句只支持上下文管理协议(也就是__enter__和__exit__)的对象,以此要定义一个包含着两个方法的类。例如定义一个拷贝列表的上下文管理器:
class CopyList:
def __init__(self,this_list):
self.this_list=this_list
def __enter__(self):
self.that_list=list(self.this_list)
return self.that_list
def __exit__(self,type,value,tb):
if type is None:
self.this_list[:]=self.that_list
return False
nums=[1,2,3,4]
with CopyList(nums) as lis:
lis.append(7)
lis.append(9)
print (nums)
[1, 2, 3, 4, 7, 9]
------------------
(program exited with code: 0)
请按任意键继续. . .
如在其中抛出异常,结果如下:
try:
with CopyList(nums) as lis:
lis.append(10)
lis.append(12)
raise RuntimeError
except RuntimeError as e:
print("运行异常")
print(nums)
运行异常
[1, 2, 3, 4, 7, 9]
-----------------
program exited with code: 0)
请按任意键继续
. . .
虽然对nums进行了操作但并没有生效。
with语句在控制list进入和离开其后的相关代码快时,允许对象管理所发生的事情。执行with语句是,执行方法__enter__指示正在进入的上下文,接受参数,并根据__exit__函数的返回值(true或false——false表示有异常)决定是否把处理后的返回值赋给as后的参数。
当控制流离开上下文时,就会执行__exit__(type,value,td)方法。如果没发生异常__exit__的三个参数均为None。其返回值将指引控制流离开上下文时接受__enter__的处理结果。
上下文管理器还可以利用contextlib模块提供的contextmanager包装器生成。以上例可该为:
@contextmanager
def Copylist(this_list):
that_list=list(this_list)
yield that_list
this_list[:]=that_list
with CopyList(nums) as lis:
lis.append(7)
lis.append(9) #无异常
print (nums)
try:
with CopyList(nums) as lis:
lis.append(10)
lis.append(12)
raise RuntimeError #设定异常
except RuntimeError as e:
print("运行异常")
print(nums)
[1, 2, 3, 4, 7, 9, 7, 9]
运行异常
[1, 2, 3, 4, 7, 9, 7, 9]
------------------
(program exited with code: 0)
请按任意键继续. . .
with指引流进入上下文,函数接受参数并把值作为__enter__的返回值传递给yield,然后调用__exit__方法,调用__exit__方法时,执行将在yield语句后恢复。如上下文引发异常,它将以异常形式出现在生成器中。
所有包含上下文管理协议的对象或被contextmanager包装的函数都可以使用with语句。
____
11.2.5 使用文件的基本方法
1、读的方法read(n)
n字节数,可选参数,默认为全部读取。
with open('xx.txt','r') as f:
word=f.read()
print(word)
你好Python,你好Python,你好Python,你好Python,你好Python
你好sys,你好sys,你好sys,你好sys,你好sys,你好sys,你好sys.
别忘了调用方法close将文件关闭。别忘了调用方法close将文件关闭。别忘了调用方法clos
e将文件关闭。别忘了调用方法close将文件关闭。别忘了调用方法close将文件关闭。别忘
了调用方法close将文件关闭。别忘了调用方法close将文件关闭。别忘了调用方法close将
文件关闭。别忘了调用方法close将文件关闭。别忘了调用方法close将文件关闭。别忘了调
用方法close将文件关闭。别忘了调用方法close将文件关闭。别忘了调用方法close将文件
关闭。别忘了调用方法close将文件关闭。别忘了调用方法close将文件关闭。别忘了调用方
法close将文件关闭。别忘了调用方法close将文件关闭。别忘了调用方法close将文件关闭
。
------------------
(program exited with code: 0)
请按任意键继续. . .
读取部分字节:
print('*'*80)
with open('xx.txt','r') as bs:
byte=bs.read(10)
print(byte)
***************************************
你好Python,你
------------------
(program exited with code: 0)
请按任意键继续. . .
2、读的方法readline()
按行读取:
with open(r'xx.txt') as li:
lis=li.readline()
print(lis)
你好Python,你好Python,你好Python,你好Python,你好Python
------------------
(program exited with code: 0)
请按任意键继续. . .
with open(r'xx.txt')as li:
lis=li.readline()
for i in range(4):
print(str(i)+':'+lis,end='')
0:你好Python,你好Python,你好Python,你好Python,你好Python
1:你好Python,你好Python,你好Python,你好Python,你好Python
2:你好Python,你好Python,你好Python,你好Python,你好Python
3:你好Python,你好Python,你好Python,你好Python,你好Python
------------------
(program exited with code: 0)
请按任意键继续. . .
3、读的方法readlines()
读取所有行。
with open('xx.txt','r') as lis:
lines=lis.readlines()
pprint.pprint(lines)
print(':'*80)
for i in lines:
print(i)
['你好Python,你好Python,你好Python,你好Python,你好Python\n',
'你好sys,你好sys,你好sys,你好sys,你好sys,你好sys,你好sys.\n',
'别忘了调用方法close将文件关闭。别忘了调用方法close将文件关闭。别忘了调用方法cl
ose将文件关闭。别忘了调用方法close将文件关闭。别忘了调用方法close将文件关闭。别
忘了调用方法close将文件关闭。别忘了调用方法close将文件关闭。别忘了调用方法close
将文件关闭。别忘了调用方法close将文件关闭。别忘了调用方法close将文件关闭。别忘了
调用方法close将文件关闭。别忘了调用方法close将文件关闭。别忘了调用方法close将文
件关闭。别忘了调用方法close将文件关闭。别忘了调用方法close将文件关闭。别忘了调用
方法close将文件关闭。别忘了调用方法close将文件关闭。别忘了调用方法close将文件关
闭。']
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
你好Python,你好Python,你好Python,你好Python,你好Python
你好sys,你好sys,你好sys,你好sys,你好sys,你好sys,你好sys.
别忘了调用方法close将文件关闭。别忘了调用方法close将文件关闭。别忘了调用方法clos
e将文件关闭。别忘了调用方法close将文件关闭。别忘了调用方法close将文件关闭。别忘
了调用方法close将文件关闭。别忘了调用方法close将文件关闭。别忘了调用方法close将
文件关闭。别忘了调用方法close将文件关闭。别忘了调用方法close将文件关闭。别忘了调
用方法close将文件关闭。别忘了调用方法close将文件关闭。别忘了调用方法close将文件
关闭。别忘了调用方法close将文件关闭。别忘了调用方法close将文件关闭。别忘了调用方
法close将文件关闭。别忘了调用方法close将文件关闭。别忘了调用方法close将文件关闭
。
------------------
(program exited with code: 0)
请按任意键继续. . .
它输出了一个有换行符的列表。
4、写的方法write(string)
with open(r'xx.txt','w') as w:
w.write('这\n是\n一\n个\nPython\n程序')
xx.txt文件更新为:
这
是
一
个
Python
程序
5、写的方法writelines(list)
输入列表内容。
lis=['做','程序','是一件','快乐的事!']
with open(r'xx.txt','w') as l:
l.writelines(lis)
xx.txt文件更新为:
做程序是一件快乐的事!
lis列表字符串可以加换行符以逐行输入。此方法可结合读方法readlines实现文件内容拷贝:
with open(r'xx.txt') as r:
w=open(r'yy.txt','w')
rs=r.readlines()
w.writelines(rs)
11.3 迭代文件
在本节的所有示例中,我都将使用一个名为process的虚构函数来表示对每个字符或行所做的处理,你可以用自己的喜欢的方式实现这个函数。下面是一个简单的示例:
def process(string):
print('Processing:', string)
更有用的实现包括将数据存储在数据结构中、计算总和、使用模块re进行模式替换以及添加行号。
另外,要尝试运行这些示例,应将变量filename设置为实际使用的文件的名称。
11.3.1 每次一个字符(或字节)
一种最简单(也可能是最不常见)的文件内容迭代方式是,在while循环中使用方法read。
with open(filename) as f:
char = f.read(1)
while char:
process(char)
char = f.read(1)
以不同的方式编写循环:
with open(filename) as f:
while True:
char = f.read(1)
if not char: break
process(char)
11.3.2 每次一行
with open(filename) as f:
while True:
line = f.readline()
if not line: break
process(line)
11.3.3 读取所有内容
1、使用read迭代字符:
with open(filename) as f:
for char in f.read():
process(char)
2、使用readlines迭代行:
with open(filename) as f:
for line in f.readlines():
process(line)
11.3.4 使用 fileinput 实现延迟行迭代
这里的延迟只是指延迟是因为它只读取实际需要的文本部分。
import fileinput
for line in fileinput.input(filename):
process(line)
11.3.5 文件迭代器
方式1:
with open(filename) as f:
for line in f:
process(line)
方式2:
for line in open(filename):
process(line)
与其他文件一样,sys.stdin也是可迭代的,因此要迭代标准输入(比如input输入)中的所有行,可
像下面这样做:
import sys
for line in sys.stdin:
process(line)
import sys
for line in sys.stdin:
print(line)
这是Python
这是Python
写文件比读文件难。
写文件比读文件难。
(待续)