011.Python之文件打开的模式与指针的移动

一、文件的打开模式

(一)控制文件读写操作的模式

1.模式r:只读(默认的模式)

(1)特点:

​ 文件不存在时报错,文件存在时文件指针跳到文件开头。

2.模式w:只写

(1)特点:

​ 文件不存在时创建空文件,文件存在时清空文件,并且文件指针跳到文件开头。

3.模式a:之追加写

(1)特点:

​ 文件不存在时创建空文件,文件存在时文件指针跳到文件末尾。

4.总结:w与a的异同

(1)相同点:

​ 在打开文件不关闭的情况下,连续的写入,新的内容永远跟在老的内容之后。

(2)不同点:

​ 重新打开文件,w模式会清空老的内容,而a模式会保留老的内容,并且指针跳到文件末尾。

5.案例示范:

# 示范一:注册功能
name = input('your name :').strip()
# 做合法性校验
# 1.如果输入的用户名包含特殊字符  让用户重新输入
# 2.如果输入的用户名已经存在也重新输入
pwd = input('your password :').strip()
# 做合法性校验:
# 1.密码的长度
# 2.如果密码包含特殊字符则重新输入
f_txt = open('user.txt',mode='at',encoding='utf-8')
f_txt.write('%s:%s\n' %(name,pwd))
f_txt.close()

# 示范2:登录功能
inp_name = input("your name: ").strip()
inp_pwd = input("your pwd: ").strip()

f_txt = open('user.txt',mode='rt',encoding='utf-8')
for line in f_txt:
    user,pwd=line.strip('\n').split(':')
    if inp_name == user and inp_pwd == pwd:
        print('login successful')
        break
else:
    print('user or password error')

f_txt.close()

(二)控制文件内读写内容的模式

1.模式t:文本模式(默认)

(1)特点:

​ 读写都是以str字符串为单位,一定要指定encoding参数。

# a.txt 'hello嘿嘿嘿哈哈哈'
f_txt = open('a.txt', mode='rt', encoding='utf-8')
res = f_txt.read()
print(res)  # hello嘿嘿嘿哈哈哈
f_txt.close()

2.模式b:bytes模式

(1)特点:

​ 读写都是以bytes为单位,一定不能指定encoding参数。

# a.txt 'hello嘿嘿嘿哈哈哈'
f_txt = open('a.txt', mode='rb')
data = f_txt.read()
# print(data, type(data))  # b'hello\xe5\x98\xbf\xe5\x98\xbf\xe5\x98\xbf\xe5\x93\x88\xe5\x93\x88\xe5\x93\x88' <class 'bytes'>
print(data.decode('utf-8'))  # hello嘿嘿嘿哈哈哈
f_txt.close()

f_txt = open('a.txt', mode='wb')
f_txt.write("张三&罗翔".encode('utf-8'))  # '张三&罗翔'覆盖原内容
f_txt.close()

3.上下文管理with

​ 借助上下文管理,可以帮助我们不用专门去关闭文件,python解释器自动帮助我们关闭打开的文件,释放系统资源。

with open() as f_txt, open() as f1:
    f_txt.read()

4.补充:+模式,可读可写

t、b模式必须与r、w、a模式联用。

+模式必须与r、w、a模式联用:r+、w+、a+

(1)rt与r+t比较:
1) rt:只读文本模式(默认的模式,如果不指定模式,就会默认此模式)
# a.txt 'hello嘿嘿嘿哈哈哈'
with open('a.txt', mode='rt', encoding='utf-8') as f_txt:
    res = f_txt.tell()
    res1 = f_txt.read()
    res2 = f_txt.tell()
    print(res, res1, res2)  # 0 hello嘿嘿嘿哈哈哈 23

2) r+t:可读可写文本模式,开头就写类似wt模式,对原内容进行覆盖,可能会造成乱码。在读完内容之后,文件指针移动到末尾,写入内容之后,如三个汉字,会返回3个字符的长度,此时文件指针仍在末尾,无法读取出有效内容,文件指针在写入三个汉字后,文件指针移动9个字节。
# a.txt 'hello嘿嘿嘿哈哈哈'
with open('a.txt', mode='r+t', encoding='utf-8') as f_txt:
    res = f_txt.tell()
    # res0 = f_txt.write('嚯嚯嚯')  # 必须读完再写,否则会覆盖原来的内容,造成乱码
    res1 = f_txt.read()
    res2 = f_txt.tell()
    res3 = f_txt.write('嚯嚯嚯')
    res4 = f_txt.read()
    res5 = f_txt.tell()
    print(res, res1, res2, res3, res4, res5)  # 0 hello嘿嘿嘿哈哈哈 23 3  32

(2)wt与w+t比较:
1) wt:只写文本模式,不可读,报错后文件清空,也没有执行写的操作
# a.txt 'hello嘿嘿嘿哈哈哈'
with open('a.txt', mode='wt', encoding='utf-8') as f_txt:
    res = f_txt.tell()
    # res0 = f_txt.read()  # io.UnsupportedOperation: not readable
    res1 = f_txt.write('hello哈哈哈')
    res2 = f_txt.tell()
    print(res, res1, res2)  # 0 8 14
                            #开始指针位置,写入字符个数,写入之后指针位置

2) w+t:可读可写文本模式,但是无论文件指针在何处,都无法读取出内容
# a.txt 'hello嘿嘿嘿哈哈哈'
with open('a.txt', mode='w+t', encoding='utf-8') as f_txt:
    res = f_txt.tell()
    res0 = f_txt.read()
    res1 = f_txt.write('hello哈哈哈')
    res2 = f_txt.read()
    res3 = f_txt.tell()
    print(res, res0, res1, res2, res3)  # 0  8  14
(3)at与a+t比较:
1) at:只追加写文本模式
# a.txt 'hello嘿嘿嘿哈哈哈'
with open('a.txt', mode='at', encoding='utf-8') as f_txt:
    res = f_txt.tell()
    # res0 = f_txt.read()  # io.UnsupportedOperation: not readable
    res1 = f_txt.write('hello哈哈哈')
    res2 = f_txt.tell()
    print(res, res1, res2)  # 23 8 37
# 最新文件内容:hello嘿嘿嘿哈哈哈hello哈哈哈

2) a+t:可读可写文本模式,写只追加
# a.txt 'hello嘿嘿嘿哈哈哈'
with open('a.txt', mode='a+t', encoding='utf-8') as f_txt:
    res = f_txt.tell()
    f_txt.seek(0, 0)
    res0 = f_txt.read()
    f_txt.seek(0, 0)
    res1 = f_txt.write('hello哈哈哈')
    res2 = f_txt.tell()
    print(res, res0, res1, res2)  # 23 hello嘿嘿嘿哈哈哈 8 37
# 最新文件内容:hello嘿嘿嘿哈哈哈hello哈哈哈

二、文件操作的其他方法

(一)读相关的方法

1) f.read()  # 读取所有内容,执行完该操作后,文件指针会移动到文件末尾。
# read(n)注意:在t模式下,括号内的参数n值得是字符数,b模式下指的是字节数!

2) f.readline()  # 从当前指针位置开始读取一行内容,光标移动到第二行首部

3) f.readlines()  # 读取每一行内容,存放于列表中
# 强调:
# f.read()与f.readlines()都是将内容一次性读入内容,如果内容过大会导致内存溢出,若还想将内容全读入内存,则必须分多次读入,有两种实现方式:
# 方式一
with open('a.txt',mode='rt',encoding='utf-8') as f:
    for line in f:
        print(line) # 同一时刻只读入一行内容到内存中

# 方式二
with open('1.mp4',mode='rb') as f:
    while True:
        data=f.read(1024) # 同一时刻只读入1024个Bytes到内存中
        if len(data) == 0:
            break
        print(data)
4) f.readable()  # 判断文件是否可读

(二)写相关的方法

1) f.write('1111\n222\n')  # 针对文本模式的写,需要自己写换行符
f.write('1111\n222\n'.encode('utf-8'))  # 针对b模式的写,需要自己写换行符

2) f.writelines(['333\n','444\n'])  # 文件模式
f.writelines([bytes('333\n',encoding='utf-8'),'444\n'.encode('utf-8')]) #b模式
3) f.writable()  # 文件是否可读

4) f.flush()  # 立刻将文件内容从内存刷到硬盘

(三)其他方法

1) f.closed  # 文件是否关闭

2) f.encoding  # 获取文件的编码格式,如果文件打开模式为b,则没有该属性

3) f.name  # 获取文件名

4) f.truncate(n)  # 从文件开头往后数n个字节保留下来,其余全部删除
				  # 如果n不指定,则从文件开头往后数指针当前所在的位置,其余全部删除

三、控制文件内指针移动

(一)控制文件指针移动的单位

1.控制文件指针移动的单位都是字节;

2.例外情况:t模式下的read(n),代表的是n个字符,此外代表的全都是字节。

with open('f.txt', mode='rt', encoding='utf-8') as f:
    data = f.read(6)  # 6个字符
    print(data)

with open('f.txt', mode='rb') as f:
    # data=f.read(6) # 6个字节
    data = f.read(8)  # 8个字节
    print(data.decode('utf-8'))

3.f.seek(offset,whence)

f.seek(n,模式) # n代表的移动的字节个数

(二)控制文件指针移动的三种模式

1.模式0:

参照文件的开头开始移动(只有0模式可以在t模式下使用,1、2模式只能在b模式下使用)

# a.txt用utf-8编码,内容如下(abc各占1个字节,中文“你好”各占3个字节)
abc你好

# 0模式的使用
with open('a.txt',mode='rt',encoding='utf-8') as f:
    f.seek(3,0)     # 参照文件开头移动了3个字节
    print(f.tell()) # 查看当前文件指针距离文件开头的位置,输出结果为3
    print(f.read()) # 从第3个字节的位置读到文件末尾,输出结果为:你好
    # 注意:由于在t模式下,会将读取的内容自动解码,所以必须保证读取的内容是一个完整中文数据,否则解码失败

with open('a.txt',mode='rb') as f:
    f.seek(6,0)
    print(f.read().decode('utf-8')) #输出结果为: 好

2.模式1:

参照指针当前所在的位置(只能在b模式下使用)

# 1模式的使用
with open('a.txt',mode='rb') as f:
    f.seek(3,1) # 从当前位置往后移动3个字节,而此时的当前位置就是文件开头
    print(f.tell()) # 输出结果为:3
    f.seek(4,1)     # 从当前位置往后移动4个字节,而此时的当前位置为3
    print(f.tell()) # 输出结果为:7

3.模式2:

参照文件末尾的位置(只能在b模式下使用)

# a.txt用utf-8编码,内容如下(abc各占1个字节,中文“你好”各占3个字节)
abc你好

# 2模式的使用
with open('a.txt',mode='rb') as f:
    f.seek(0,2)     # 参照文件末尾移动0个字节,即直接跳到文件末尾
    print(f.tell()) # 输出结果为:9
    f.seek(-3,2)     # 参照文件末尾往前移动了3个字节
    print(f.read().decode('utf-8')) # 输出结果为:好

(三)使用案例:模拟程序记录日志的功能

# 模拟记录日志
import time
for i in range(10000):
    with open('access.log', mode='at', encoding='utf-8') as f:
        t = time.strftime('%Y-%m-%d %H:%M:%S')
        content = '张三给李四转了%s毛钱' %i
        
        msg = f'{t} {content}\n'
        f.write(msg)
    time.sleep(3)
# 监控日志
import time
with open('access.log', mode='rb') as f:
    f.seek(0,2)
    while True:
        line = f.readline()
        if len(line) == 0:
            time.sleep(0.3)
        else:
            print(line.decode('utf-8'), end='')
 %H:%M:%S')
        content = '张三给李四转了%s毛钱' %i
        
        msg = f'{t} {content}\n'
        f.write(msg)
    time.sleep(3)
# 监控日志
import time
with open('access.log', mode='rb') as f:
    f.seek(0,2)
    while True:
        line = f.readline()
        if len(line) == 0:
            time.sleep(0.3)
        else:
            print(line.decode('utf-8'), end='')
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值