【2022-06-30】Python文件处理(二)
Python文件处理
文件模式补充说明
- 针对open() 函数支持的文件打开模式,做出如下补充:
| 模式 | 描述说明 | 
|---|---|
| t | 文本模式(默认) | 
| x | 写模式,新建一个文件,如果该文件已存在,则会报错 | 
| b | 二进制模式 | 
| + | 打开一个文件进行更新(可读可写) | 
| U | 通用换行模式(不推荐使用) | 
| r | 以只读的方式打开文件,文件的指针会放在文件的开头,这是默认模式 | 
| rb | 以二级制格式打开一个文件用于只读, 文件指针将会放在文件的开头。这是默认模式。一般用于非文本文件如图片等 | 
| r+ | 打开一个文件用于读写。文件指针将会放在文件的开头 | 
| rb+ | 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。一般用于非文本文件如图片等 | 
| w | 打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 | 
| wb | 以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。 | 
| w+ | 打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 | 
| wb+ | 以二进制格式打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。 | 
| a | 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 | 
| ab | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 | 
| a+ | 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。 | 
| ab+ | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。 | 
下图很好的总结了这几种模式:

支持原创,以上内容摘自:https://www.runoob.com/python/python-files-io.html
文件内光标的移动
"""只有在文本模式使用的情况下,read控制的是字符,其余情况都是以字节为单位
userinfo.txt  =  libai say 人生得意须尽欢,莫使金樽空对月
with open(r'userinfo.txt', 'r', encoding='utf8') as f:
    data = f.read(30)                      #  在文本模式下,read括号内的数字表示读取几个字符
    print(data)                            #  libai say 人生得意须尽欢,莫使金樽空对月
    
with open(r'userinfo.txt', 'rb') as f:
    data = f.read(30)      #   在二进制模式下,read括号内的数字表示读取几个字节(英文表示一个bytes,中文表示三个bytes)
    print(data)  # b'libai say \xe4\xba\xba\xe7\x94\x9f\xe5\xbe\x97\xe6\x84\x8f\xe9\xa1\xbb\xe5\xb0\xbd\xe6\xac'
    
查看目前光标移动的位移量:
print(f.tell())      # 获取光标移动的字节数
如何使用代码控制光标的移动
seek(offset,whence)
     offset   控制光标移动的位移量(以字节为单位)
     whence   移动的模式
  		0	 基于文件开头的位置往后移动多少字节
  		1	 基于光标当前所在的位置移动多少字节
  		2        基于文件末尾移动多少字节
  		
  	1和2只能在二进制模式下使用
    
#     with open(r'userinfo.txt', 'rb') as f:
#     data = f.read(4)
#     print(data.decode('utf8'))                   # liba
#     # f.seek(-2, 1)
#     # print(data.decode('utf8'))                   # liba
#     f.seek(-2, 2)
#     print(data.decode('utf8'))                      # liba
  		
# 小练习:实现动态查看最新一条日志的效果
import time
with open('access.log', 'rb') as f:
    f.seek(0, 2)
    while True:
        line = f.readline()
        if len(line) == 0:
            # 没有内容
            time.sleep(0.5)
        else:
            print(line.decode('utf-8'), end='')
文件内数据的修改
机械硬盘存储数据的原理
	1.数据的修改 其实是覆盖写
	2.数据的删除 占有态自由态
# 文件桃园三结义.txt内容如下
刘备     东汉    100    30     10086
关羽     东汉    95     100    10086
张飞     东汉    70     95     10086
# 执行操作
with open('桃园三结义.txt',mode='r+t',encoding='utf-8') as f:
    f.seek(9)
    f.write('<周瑜打黄盖>')
    
# 文件修改后的内容如下
刘备<周瑜打黄盖> 100     30     10086
关羽     东汉    95     100    10086
张飞     东汉    70     95     10086
PS:
# 1、硬盘空间是无法修改的,硬盘中数据的更新都是用新内容覆盖旧内容
# 2、内存中的数据是可以修改的
代码修改文件的方式
	1.覆盖写
    	先读取文件内容到内存 在内存中完成修改 之后w模式打开该文件写入
	2.重命名
    	先读取文件内容到内存 在内存中完成修改 之后保存到另外一个文件中
       再将原文件删除 将新的文件重命名为原文件
文件修改方式一:覆盖写
# 将文件内容发一次性全部读入内存,然后在内存中修改完毕后再覆盖写回原文件
# 优点: 在文件修改过程中同一份数据只有一份
# 缺点: 会过多地占用内存,当数据量过大时,容易造成内存溢出
with open('123.txt',mode='rt',encoding='utf-8') as f:
    data=f.read()
with open('123.txt',mode='wt',encoding='utf-8') as f:
    f.write(data.replace('张三','NB'))
    
  
文件修改方式二:重命名
    
# 以读的方式打开原文件,以写的方式打开一个临时文件,一行行读取原文件内容,修改完后写入临时文件...,删掉原文件,将临时文件重命名原文件名
# 优点: 不会占用过多的内存空间
# 缺点: 在文件修改过程中同一份数据存了两份
import os
with open('123.txt',mode='rt',encoding='utf-8') as read_f,\
        open('.123.txt.swap',mode='wt',encoding='utf-8') as wrife_f:
    for line in read_f:
        wrife_f.write(line.replace('NB','张三'))
os.remove('123.txt')          # 删除文件
os.rename('.123.txt.swap','123.txt')       # 重命名文件
课题演练
1.编写用户注册、登录功能并封装为函数
def user_register():
    print("""
            1.注册功能
            2.登录功能
            3.退出程序
            """)
    func_id = input('请输入功能编号>>>:').strip()
    if func_id == '1':
        # 1.获取用户名
        username = input('请输入用户名>>>:').strip()
        # 2.判断当前用户名是否已存在
        # 2.1.读取数据文件
        with open(r'userinfo.txt', 'r', encoding='utf8') as f:
            # 2.2.循环获取文件内容(一个个用户数据)
            for line in f:  # jason|123    kevin|321    tony|222
                # 2.3.拆分出真实用户名 比对
                real_name = line.split('|')[0]
                # 2.4.判断用户名书否已存在
                if username == real_name:
                    print('用户名已存在')
                    break
            else:
                # 一定要理解循环与break continue else的组合使用
                password = input('请输入密码>>>:')
                # 3.构造用户数据
                user_data = '%s|%s\n' % (username, password)
                # 4.打开并写入文件
                with open(r'userinfo.txt', 'a', encoding='utf8') as f:
                    f.write(user_data)
                # 5.温馨提示
                print(f'用户{username}注册成功')
def user_login():
    print("""
                1.注册功能
                2.登录功能
                3.退出程序
                """)
    func_id = input('请输入功能编号>>>:').strip()
    if func_id == '2':
        # 1.获取用户数据
        username = input('username>>>:').strip()
        password = input('password>>>:').strip()
        # 2.读取文件内容
        with open(r'userinfo.txt', 'r', encoding='utf8') as f:
            # 2.1.循环读取每个真实用户的数据
            for line in f:  # oscar|666    jerry|789
                # 2.2.拆分真实用户名和密码
                real_name, real_pwd = line.split('|')  # 注意密码后面有换行符
                # 2.3.判断用户输入的数据与真实数据是否一致
                if username == real_name and password == real_pwd.rstrip('\n'):
                    print('登录成功')
                    break
            else:
                print('用户名或密码错误')
def user_exit():
    print("""
            1.注册功能
            2.登录功能
            3.退出程序
    """)
    func_id = input('请输入功能编号>>>:').strip()
    if func_id == '3':
        print('欢迎下次再来哦')
    else:
        print('输入不合法!!!')
user_register()
user_login()
user_exit()

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号