基本概念
- 打开文件的模式有三种纯净模式:r(默认的)、 w 、a
- 控制操作文件内容格式的两种模式:t(默认的)、b
大前提:tb模式均不能单独使用,必须与纯净模式结合使用
t文本模式
-
- 1.读写文件都是以字符串为单位的
- 2.只能针对文本文件
- 3.必须指定encoding参数
b二进制模式
-
- 1.读写文件都是以bytes/二进制位单位的
- 2.可以针对所有文件
- 3.一定不能指定encoding参数
二.打开文件模式详解
- 1.只读模式(rt):在文件不存在时则报错,文件存在文件内指针直接跳到文件开头
with open(r'a.txt',mode = 'rt',encoding = 'utf-8') as f: #r的意思是之后跟的是一个纯路径
print(f.readlines())
-
- 用户认证功能
user_name = input('请输入你的用户名:').strip()
user_psw = input('请输入你的密码:').strip()
with open(r'db.txt',mode = 'rt',encoding = 'utf-8') as f:
for line in f:
x,y = line.strip('\n').split(':')
if user_name == x and user_psw == y:
print('登录成功')
break
else:
print('用户名或密码错误')
- w只写模式(wt):在文件不存在时会创建空文档,文件存在会清空文件,指针跑到文件开头
with open(r'b.txt',mode = 'wt',endocing = 'utf-8') as f:
print(f.writable()) #判断 可写
print(f.readable()) #判断 不可读
f.write('雷猴\n')
f.write('我猴\n') #强调:在文件不关闭的情况下,写入是从指针当前位置往下写,如果文件关闭从新打开,之前写入的会被清空
f.write('大噶猴\n')
f.write('111\n222\n333\n') #连续写入可以直接连着写,注意换行符\n,换行也是字符一定记得写
'''
我们来定义一个变量列表
用for循环把它的每个量取出在写入文件中
'''
lines = ['111','222','333']
for line in lines: #for循环的写法
f.write(lines)
f.writelines(lines) #writelines方法同样的效果
-
- 注册功能:
user_name = input('请设置你的用户名>>:')
user_psw = input('请设置你的密码>>:')
with open(r'b.txt',mode = 'wt',encoding = 'utf-8') as f:
info = '%s:%s\n' %(user_name,user_psw)
f.write(info)
这里会有一个问题:每一次注册,w只读模式的定义,每次打开文件存在会清空文件,每次注册上一个人注册的数据就不见了
- a之追加写模式(at):在文件不存在是会创建空文档,文件存在时,文件指针会直接移动到文件最后
with open(r'c.txt',mode = 'at',encoding = 'utf-8') as f:
print(f.resdable()) #不可读,会报错
print(f.writable()) #可写
f.write('1111\n')
with open(r'c.txt',mode = 'at',encoding = 'utf-8') as f:
f.write('2222\n') #不管关不关文件,之前的数据都不会被清空,可以用这个实现注册
-
- 注册功能:
user_name = input('请设置你的用户名>>:')
user_pwd = input('请设置你的密码>>:')
with open('c.txt',mode = 'at', encoding = 'utf-8') as f:
info = '%s:%s\n' %(user_name,user_pwd)
f.write(info)
- b:读写都是以二进制为单位
- rb:
with open('b.txt',mode='rb') as f:
data=f.read()
print(data,type(data)) #输出二进制,类型bytes
print(data.decode('utf-8')) #解码成字符,相当于变成rt
with open('d.txt','wb') as f:
f.write('你好'.encode('utf-8')) #写入以utf-8编码成二进制
'''
以b的文件打开方式也能完成对文件的只读、只写、只增加写,
只是他没有t的文件打开方式那么方便
'''
with open('1.png',mode='rb') as f:
data=f.read()
with open('2.png',mode='wb') as f:
data=f.write(data)
'''
b模式可以对任意文件进行读写,图片、视频都可以
我们可以发现上面的代码的读写,是实现了1.png文件的复制、粘贴
但是如果直接全读,文件过大,内存就爆了,所以我们有要一行一行读,用for循环
'''
#拷贝工具
src_file=input('源文件路径: ').strip()
dst_file=input('目标文件路径: ').strip()
with open(r'%s' %src_file,mode='rb') as read_f,open(r'%s' %dst_file,mode='wb') as write_f:
for line in read_f:
# print(line)
write_f.write(line)
文件内指针的移动
大前提:文件内指针的移动是以Bytes为单位的,唯独t模式下的read读取内容个数是以字符为单位的
f.read(3)
with open('a.txt',mode='rt',encoding='utf-8') as f:
data=f.read(3) #这个读个数是以字符为单位的
print(data)
with open('a.txt',mode='rb') as f:
data=f.read(3) #这个读个数是以字节Bytes为单位的
print(data.decode('utf-8'))
-
f.seek(指针移动的字节数,模式控制):控制指针的移动
-
- 0(默认模式):该模式代表指针移动的字节数是以文件开头做参照物的
- 1:该模式代表指针移动的字节数是以当前位置做参照物的
- 2:该模式代表指针移动的字节数是以文件末尾做参照物的
强调:其中0模式可以在t模式和b模式使用,而1跟2模式只能在b模式下使用
f.tell()查看文件指针当前距离文件开头的位置
0模式详解:
with open(r'c.txt',mode = 'rt',encoding = 'utf-8') as f:
f.seek(4,0)
print(f.tell)
print(f.read())
with open(r'c.txt',mode = 'rb') as f:
#f.seek(4,0)
f.seek(2,0) #指针移动2bytes不到一个中文字符
print(f.tell())
print(f.read().decode('utf-8')) #报错
1模式
with open('a.txt',mode='rb') as f:
f.seek(3,1)
print(f.tell()) #计算时从开头开始计算的
f.seek(4,1)
print(f.tell()) #返货7
print(f.read().decode('utf-8'))
2模式
with open('a.txt',mode='rb') as f:
f.seek(-9,2) #指针在末尾,只能往回带移动指针
data=f.read()
print(data.decode('utf-8'))
- 根据2模式可以写一个日记的读写功能
先来分析,首先写日记,日记要存起来,如果我们只是想看当天的日记用2模式,2模式指针跳到最后,现在指针后面是没有内容的,就都不到东西。当文件被输入一个新内容后,指针后面就有内容,就可以独处内容,指针又会到最后,每次读出来的都是新输入进去的内容
# tail -f access.log
with open('access.log',mode='rb') as f:
f.seek(0,2)
while True:
line=f.readline()
if len(line) == 0:
# 没有内容
continue
else:
print(line.decode('utf-8'),end='')
#写一个输入内容的功能
import time #这个方法可以拿到实时时间用time.strftime('%Y-%m-%d %X')
with open('access.log',mode='at',encoding='utf-8') as f:
f.write('%s 下雨了alex快跑\n' %time.strftime('%Y-%m-%d %X'))
文件修改
- 须知一:
硬盘空间无法修改,硬盘中的数据更新都是用新的内容覆盖旧的内容 内存控制可以修改
with open('a.txt',mode = 'r+t',encoding = 'utf-8') as f:
f.seek(4,0)
print(f.tell())
f.write('是添加还是覆盖')
- 须知二:
文件对应的是硬盘空间,硬盘不能修改所以文件本质也不能修改,
我们看到文件的内容可以修改,是如何实现的呢?
*大的思路:*将硬盘中的文件读入内存中,在内存中修改完之后再覆盖回硬盘
-
- 具体实现分两种:
- 1.将硬盘中的文件内容一次性读入硬盘,然后在内存中修改完毕后 再覆盖到回硬盘中的原文件
- 优点:在文件修改过程中同一份数据只有一份,不会过多占用硬盘空间
- 缺点:会过多的占用内存
- 1.将硬盘中的文件内容一次性读入硬盘,然后在内存中修改完毕后 再覆盖到回硬盘中的原文件
- 具体实现分两种:
with open('db.txt',mode='rt',encoding='utf-8') as f:
data=f.read()
with open('db.txt',mode='wt',encoding='utf-8') as f:
f.write(data.replace('kevin','SB'))
-
-
- 2.以读的方式打开原文件,以写的方式打开一个临时文件,一行行的读取原文件内容,修改完后写入临时文件…删掉原文件,将临时文件重命名为原文件名
- 优点:不会占用过多内存
- 缺点:在文件修改过程中同一个数据存了两份
- 2.以读的方式打开原文件,以写的方式打开一个临时文件,一行行的读取原文件内容,修改完后写入临时文件…删掉原文件,将临时文件重命名为原文件名
-
import os
with open('db.txt',mode='rt',encoding='utf-8') as read_f,\
open('.db.txt.swap',mode='wt',encoding='utf-8') as wrife_f:
for line in read_f:
wrife_f.write(line.replace('SB','kevin'))
os.remove('db.txt') #和上面的import os,os.remove方法删除文件
os.rename('.db.txt.swap','db.txt') #和上面的import os,os.rename方法修改文件名