文件操作
一、文件的打开模式
1. 控制文件读写操作的模式(r,a,w)
(1)r:只读模式
文件不指定打开模式时会默认为r模式
文件不存在时会报错;
文件存在时,文件指针会跳到文件开头
f=open('a.txt',mode='rt',encoding='utf-8')
res = f.read()
print(res)
f.close()
(2)w:只写模式
当文件不存在会创建一个空文件,然后文件指针跳到文件开头
当文件存在时文件内容会被清空,然后文件指针跳到文件开头
f=open('a.txt',mode='wt',encoding='utf-8')
f.write('hello\n ')
f.write("你好\n") # 在f.close()执行之前可以连续写入,但是下一次操作仍会清空a.txt
f.close()
(3)a:只追加写模式
在文件不存在时则创建空文件;
文件存在时文件指针跳到文件末尾,不会清空文件
f=open('a.txt',mode='at',encoding='utf-8')
f.write('hello\n') # 文件末尾追加写'hello'
f.write('你好\n')
f.close()
-
总结:w模式与a模式的异同
相同点:在打开了文件不关闭的情况下,新的内容永远跟在文件末尾老内容之后追加写 不同点:文件关闭了重新打开的时候,w模式会将旧的文件内容清空再写入; 而a模式则会保留旧内容,文件指针跳到文件末尾
2、控制文件读写内容的模式(t、b)
t、b模式,必须与r/w/a模式联用
(1)t(文本模式)
默认模式,不指定时默认为t模式
读写都是以字符串为单位
只适用于文本文件
必须指定encoding参数(一般使用'utf-8')
打开文本文件并读取内容时比较方便
f = open('a.txt', mode='rt', encoding='utf-8')
res = f.readline()
print(res)
f.close()
(2)b(binary,二进制模式)
读写都是以字节(bytes)为单位
适用于一切文件
一定不能指定encoding参数
打开文本文件读取内容时比较麻烦,读写都需要编码、解码,没有t模式简洁直接
f = open('a.txt', mode='rb', encoding='utf-8')
res = f.readline()
print(res.decode('utf-8'))
f.close()
二、补充知识点
1、with上下文管理
with open() as f1, open() as f2:
f1.read()
f2.write()
优点:
代码简洁,自动调用 f1.close() 和 f2.close() 回收操作系统资源
2、+模式
+ 必须与 r/w/a 模式联用
+t:t模式下的可读可写模式,可以省略t,默认为t模式,读写都是以字符串为单位,如:r+t, w+t, a+t
+b:b模式下的可读可写模式,读写都是以bytes为单位,如:r+t, w+t, a+t
因为+模式并没有改变r、w、a模式原有的特点,所以平时写代码很少用
3、默认的rt模式
在不指定文件打开模式的情况下,默认为rt模式
三、文件操作的其他方法
- 读相关的方法
1、f.readline()
作用:只读取一行内容
with open('a.txt', mode='rt',encoding='utf-8') as f:
data1 = f.readline() #每次读取一行
data2 = f.readline()
2、f.readlines()
将所有内容以line为单位转换成一个个字符串并保存在列表中(类似于使用for循环,将每一行的内容添加进一个空列表)
with open('a.txt', mode='rt',encoding='utf-8') as f:
# l = []
# for line in f:
# l.append(line)
list = f.readlines() # 上面的三行代码可以使用f.readlines()代替
print(list) # 得到一个类似于['aaa\n', 'bbb\n', 'ccc\n']这种的列表
- 写相关的方法
3、f.writelines()
作用:相当于使用一个for循环将列表中的值(字符串)依次写进文件
f.writelines()也可以用于字典,但是只能写入字典的key,且key必须是str类型,否则会报错
with open('b.txt', mode='wt', encoding='utf-8') as f:
lines = ["111\n", "222\n", "333\n"]
# for line in lines:
# f.write(line)
f.writelines(lines) # 上面的for循环可以使用.writelines() 方法代替
- 其他
4、f.flush()
f.flush紧接着f.write()使用,可以使数据立刻写进硬盘方便保存和立即调用
但是很少用,因为它会使程序的I/O增加,从而影响程序的运行效率
with open('a.txt', mode='at', encoding='utf-8') as f:
f.write('hello')
f.flush()
5、f.truncate()
不常用,了解即可
f.truncate(n) 从文件开头往后数n个字节保留下来,后面全部删除
f.truncate() 从文件指针当前所在的位置开始记(往前全部保留),往后全部删除
6、f.name 、f.closed
f.name 取的是文件路径,f.closed判断文件是否已经关闭
with open('a.txt', mode='wt', encoding='utf-8') as f:
print(f.name) # a.txt
print(f.closed) # False
四、控制文件内的指针移动
1、文件指针移动的单位
只有在t模式下的f.read(n)中,n 指的是字符个数
其余所有的主动、被动的指针移动,都是以bytes为单位的
2、主动/单纯的指针移动 f.seek(x, y)
f.seek(x, y)中,x代表的是移动字节的个数,y代表的是指针移动的模式
(1)0 模式
参照物是文件的开头,可以在t、b模式下使用(只有0模式可以在t模式下正常使用)
with open('a.txt', mode='rt', encoding='utf-8') as f:
f.seek(3, 0) # 指针在文件的开头,向后移动3个字节
print(f.tell()) # 3 f.tell()是计算从文件开头算起,当前指针的位置
(2)1 模式
指针移动的参照物为指针当前位置,只能在b模式下使用
with open('d.txt', mode='rb') as f:
f.read(1) # 指针被动移动一个字节
print(f.tell()) # 1 当前位置
f.seek(2,1) # 在当前位置往后移动2个字节
print(f.tell()) # 3
(3) 2 模式
参照物为文件末尾,只能在b模式下使用
t模式下使用时,只能使用f.seek(0, 2)
with open('a.txt', mode='rb') as f:
f.seek(-3, 2) # 指针移动到倒数第三个字符
print(f.tell())
五、文件修改的两种方式
硬盘没有修改文件的概念,所谓的文件修改都是以新数据覆盖旧数据实现改变的
但是内存是可以修改的,我们可以借助内存来模拟实现文件的修改
具体来讲,有两种方法可以实现文件修改的操作
1、方式一原理
-
步骤:
1、将硬盘中文件的内容全部读入内存中去
2、在内存中将文件一次性修改完毕
3、将修改完的内容覆盖回原文件 -
总结:
优点:不耗费硬盘,硬盘中的文件只有一份
缺点:耗费内存 ,当文件过大时会占满内存 -
代码:
with open('a.txt', mode='rt',encoding='utf-8') as f1:
data = f1.read()
res = data.raplace('hello', '你好')
with open('a.txt', mode='wt', encoding='utf-8') as f2:
f2.write(res)
2、方式二原理
-
步骤:
1、循环读取源文件,一行行读取内容修改,再一行行写进另一个临时文件
2、将源文件删除
3、将临时文件重命名为源文件 -
总结:
优点:不占内存,同一时刻在内存中只有一行内容
缺点:耗费硬盘,在修改过程中硬盘上会同时存放两份数据 -
代码:
import os
with open('a.txt', mode='rt', encoding='utf-8') as f1, open('.a.txt.swp', mode='wt', encoding='utf-8') as f2:
for line in f1:
res = line.repalce('hello', '你好')
f2.write(res)
os.remove('a.txt')
os.renames('.a.txt.swp', 'a.txt')