文章目录 1. 文件读写 1.1 文件 1.2 open函数 1. file参数 2. mode参数 3. encoding参数 1.3 操作文件注意事项 1. 操作文件原理 2. 操作文件步骤 3. 回收系统资源 1.4 上下文管理 2. 模式测试 2.1 只写模式 2.2 读模式 2.3 追加模式 2.4 字节串模式 2.5 附加模式 1. 让只读模式具备可写功能 2. 覆盖模式 3. 让只写模式具备可读功能 3. 文件对象方法 3.1 读系列 1. 测试环境 2. 判断是否具备可读功能 3. 读取全部数据 4. 读取n个字符 5. 读取一行数据 6. 数据按行保存到列表 3.2 写系列 1. 判断是否具备可写功能 2. 写入数据 3. 分批写入多行数据 4. 批量写入多行数据 5. 将数据刷硬盘 6. 获取文件描述符 3.3 其它方法 4. 文件指针移动 4.1 操作指针方法 4.2 t模式操作 4.3 b模式操作 4.4 注意事项 5. 及时获取文件数据 6. 文件的复制 7. 文件修改模式 7.1 文件状态 7.2 硬盘占有率高 7.3 内存占有率高 8. 可变字符串 9. 练习
1. 文件读写
1.1 文件
数据的存储可以使用变量临时存储在内存 , 也可以使用文件永久存储在硬盘中 .
之前写的代码存储的数据都是保存在变量在内存申请空间存储 , 一旦电脑断电那么数据就会消失了 ,
所以需要就程序的计算结果持久化 , 以文件的形式保存到硬盘上 . * 持久化就是将有用的数据以某种技术保存起来 , 将来可以再次取出来应用 . 文件 : 计算机提供给用户可以简单硬盘的接口 , 操作文件其实就是操作硬盘的读写功能 .
1.2 open函数
Python内置很多提供操作文件的函数 , 模块 , 常用的有open ( ) 函数 .
open ( ) 函数 : 可对文件进行读写操作 .
语法 :
def open ( file , mode = 'r' , buffering = None , encoding = None , errors = None , newline = None ,
closefd = True ) 参数 :
file : 一个包含了你要访问的文件名称的字符串值 , 通常是一个文件路径 .
mode : 打开文件的模式 , 有很多种 , 默认为读模式 .
buffering : 缓存 .
encoding : 文件使用的编码 .
errors : 指明编码和解码错误时怎么样处理,适用于文本模式 .
newline : 控制换行 , 只能用于t模式 .
closefd : 关闭文件描述符 , True表示关闭 . 返回值 :
返回一个文件对象 , Python专门给这个类型取了个名字 '文件IO包装' .
1. file参数
file参数指定文件所在的路径 . 路径问题 :
windows下路径分隔符使用的是斜杆 ' \ ' , 斜杆与某些字母组合会产生特殊含义 . 解决方式 :
* 1. 原始字符串 , 路径的字符串前面加一个r来抑制转义 . open ( r 'C:\a.txt\nb\c\d.txt' )
* 2. 反斜杠做路径分割符 , Windows默认使用斜杆最为路径分隔符 , 也支持反斜杠作 . open ( 'C:/a.txt/nb/c/d.txt' )
2. mode参数
mode参数的可以理解成两部分组成 .
* 1. 读写模式 , 是一个动作 , 需要指明这次操作是读文件 , 还是写文件 .
* 2. 文件类型 , 以什么单位读写文件 , 可以为字符串或字符集为单位 .
读写模式 : ( 默认为r , 只读模式 )
r , 只读模式 : 文件不存在报错 , 文件存在则打开 , 读取文件中的数据 .
w , 只写模式 : 文件不存在则新建 , 文件存在会清空文件中的数据 , 再写入数据 .
a , 追加模式 : 文件不存在则新建,存在则在文本的末尾追加新的数据 .
* w模式与a模式只能只能在已经存在的目录下创建文件 , 不能创建目录 . 文件类型: ( 默认为t , 读写以字符串为单位读取数据 . )
t : 读写以字符为单位读取文件数据 , 只适用于文本文件 , 必须指定encoding参数 .
b : 读写都是以字节为单位取文件数据 , 适用与任何文件 , 不能指定cencoding参数 . 简写方式 : ( 只保留值即可 . )
mode = 'r' > > 'r' 只读模式 .
mode = 'rt' > > 'rt' > > 'r' 只读模式 , 读写以字符串为单位读取文件数据 . 附加模式 :
r模式搭配 '+号' : 让读模式具备w模式的功能 , 每写入一个字符覆盖之前存在的一个字符 , 写入的数据比原有的数据少 , 会遗留原来的数据 .
w模式搭配 '+号' : 让写模式具备w模式的功能 , 会先清空在写入 .
3. encoding参数
encoding参数指定解码的格式 .
如果存数字和英文字符没有问题 , 几乎所有编码都兼容 .
在涉及中文时 , 需要严格指定编码格式 , 不指定 , 不是报错也是乱码 .
* 记住一句话 , 文件以什么编码存的 , 就要以什么编码打开 . 写操作时 : 没有指定encoding参数 , encoding = None , 默认使用utf- 8.
读操作时 : 没有指定encoding参数操作系统会使用自己默认的编码 , linux : utf- 8 , 国内Windows : GBK . encoding = 'utf8' 等同 encoding = 'utf-8'
encoding = 'utf' 不会报错 , 但是不推荐 .
1.3 操作文件注意事项
1. 操作文件原理
操作文件原理 :
文件的数据是保存是在硬盘上的 , Python程序无法直接操作硬件 ,
而是通过操作系统去提供的接口 , 去操作硬盘将数据加载到内存中进行读写操作 . Python在内存中申请一个变量 ( 文件句柄 ) 绑定这个接口 , 后序读写文件操作 , 都是拿着对象间接操作硬盘 .
这个变量就像一个遥控器一样 , 在计算机中 , 也把这样的操作方式称为 '遥控器/句柄(handler)' .
2. 操作文件步骤
使用open ( ) 函数方法操作文件的模式可以分三步 , 一是打开文件 , 二是操作文件 , 三是关闭文件 .
打开文件后会占用计算机资源 , 计算机的资源也是有限的 , 打开文件的个数也是有限的 .
当不需要使用这个文件的时候占用的资源就该及时释放 , 文件对象 . closs ( ) 方法回收系统占用的空间 .
file1 = open ( 'a.txt' , mode= 'w' )
print ( file1)
file1. close( )
file2 = open ( 'b.txt' , mode= 'w' , encoding= 'utf8' )
print ( file2)
file2. close( )
file2. write( '123' )
3. 回收系统资源
内存可分为 '程序占用的内存空间' 和 '操作系统占用的内存空间' .
Python程序结束时会自动回收变量占用的内存 ,
如果是一个进程如果打开了一个文件 , 不close , 程序结束后 , 操作系统会自动回收释放 . 文件对象不回收 , 会有什么样的影响 :
* 1. 操作系统有最大打开文件的限制 , 如果超过了打开文件会报错 .
* 2. 如果一个程序大量的读写多个不同的文件 , 不close , 超过max_open_file个数后 , 打开文件报错 .
* 3. 还有 : 如果不close , 进程退出后 , 写入的文件不会及时落盘 , 突然断电 , 可能出现丢失的情况 .
list1 = [ ]
count = 0
while True : f = open ( 'a.txt' , 'r' ) print ( f. fileno( ) ) list1. append( f) count += 1 print ( f'打开文件的个数: { count} ' )
在打开一定数量的文件后 , 文件打开操作就失败了 . ( 文件资源泄漏 )
计算机是使用二进制来表示数据的 , 因此计算机里的很多数据都是按照 2 的多少次方这样的方式来表示的 ,
默认可打开 8189 + 3 = 8192 = > 2 的 13 次方个文件 .
每一个程序启动的时候 , 都会默认打开一下三个文件 , 对应描述符 0 , 1 , 2 ( 其它描述符从 3 开始 ) :
标准输入 : 键盘 , input ( ) 通过标准输入来读数据 .
标准输出 : 显示器 , print ( ) 往标准输出文件里写数据 .
标准错误 : 显示器 .
这三个文件很特殊 , 这三个文件不是保存在磁盘里 , 而是在键盘 , 显示器当中的 . 文件资源泄漏 , 是很重要的问题 , 这个问题不会第一时间报错出来 , 在比较大的程序中 , 这问题很难发现 ,
当程序报错的时候 , 不是在我们写的那一时间报错 , 可能会在后面的时候发生文件资源泄漏 ,
这时候就不容易找出这个问题 .
不用列表来存储文件句柄的时候 , 打开的文件就不止 8189 个了 , 这个时候变量绑定新打开的文件 ,
没有被使用的文件会自动关闭回收系统资源 , 真正打开的文件始终只有一个 .
1.4 上下文管理
with 关键字 : 上下文管理 , 打开文件使用完毕后 , 会自动关闭文件回收系统资源 .
with 可以同时打开多个文件 , 同时打开一个文件会出现文件错乱的情况 . 使用格式 :
with open ( r '文件路径' , 读写模式 , 字符编码 ) as 文件句柄 : 子代码块 打开多个文件格式 :
with open ( ) as 文件句柄 1 , open ( ) as 文件句柄 2 : 子代码块 * 读写操作必须在with语句的子代码块内操作 , 缩进结束也就意味着关闭文件 , 回收资源 .
2. 模式测试
读写文件的时候有一个文件指针的概念 , 它表示着当前操作所在的位置 .
打开文件时文件指针默认在开头 , 读写数据时文件指针会向后移动 , 读写完闭之后 , 文件指针就到末尾了 .
2.1 只写模式
只写模式 : 文件不存在被创建 , 存在数据被清空 .
f . write ( '字符串' ) : 往文件写入数据 , 返回写入的字符个数 , 需要换行时 , 使用换行的转义字符 '\n' .
1. 文件不存在
with open ( r"a.txt" , mode= 'w' , encoding= 'utf-8' ) as f1: print ( f1. write( '123' ) )
2. 文件存在
with open ( r"a.txt" , mode= 'w' , encoding= 'utf-8' ) as f1: pass
2.2 读模式
只读模式 : 文件不存在报错 , 文件存在则打开 .
f . read ( ) : 读取文件全部数据 .
f . read ( n ) : 读取n个字符 .
1. 路径存在
with open ( r"a.txt" , mode= 'r' , encoding= 'utf-8' ) as f: print ( f. read( ) ) print ( f. read( 1 ) ) with open ( r"a.txt" , mode= 'r' , encoding= 'utf-8' ) as f: print ( f. read( 1 ) )
2. 路径不存在
with open ( r"c.txt" , mode= 'r' , encoding= 'utf-8' ) as f: pass
2.3 追加模式
追加模式 : 文件不存在则创建 , 文件存在则从文件的末尾追加数据 .
文件指针会移动到在文件末尾 , 新内容永远在文件的末尾开始追加 .
with open ( r"d.txt" , mode= 'a' , encoding= 'utf-8' ) as f1: print ( f1. write( '123' ) ) print ( f1. write( '456' ) ) with open ( r"d.txt" , mode= 'r' , encoding= 'utf-8' ) as f2: print ( f2. read( ) )
2.4 字节串模式
with open ( r'a.txt' , mode= 'rb' ) as f: res = f. read( ) print ( res) print ( res. decode( 'utf8' ) )
2.5 附加模式
附加模式 :
r模式搭配 '+号' : 让读模式具备w模式的功能 , 每写入一个字符覆盖之前存在的一个字符 , 写入的数据比原有的数据少 , 会遗留原来的数据 .
w模式搭配 '+号' : 让写模式具备w模式的功能 , 会先清空在写入 .
with open ( 'a.txt' , 'r' , encoding= 'utf8' ) as f: f. write( '你好!' )
with open ( 'a.txt' , 'w' , encoding= 'utf8' ) as f: f. read( )
1. 让只读模式具备可写功能
with open ( 'a.txt' , 'r+' , encoding= 'utf8' ) as f: f. write( '你好!' ) print ( f. read( ) )
2. 覆盖模式
with open ( 'a.txt' , 'r+' , encoding= 'utf8' ) as f: f. write( '123456789' ) with open ( 'a.txt' , 'r+' , encoding= 'utf8' ) as f: f. write( 'abc' )
3. 让只写模式具备可读功能
with open ( 'b.txt' , 'w+' , encoding= 'utf8' ) as f: print ( f. read( ) )
3. 文件对象方法
3.1 读系列
. readrable ( ) 判断文件对象是否用具备可读功能 , 返回一个布尔值 .
. read ( ) 读取全部数据 , t模式返回字符串类型 , b模式返回字节串类型 .
. read ( n ) 提供参数n时 , t模式返回n个字符串 , b模式返回n个字节串 .
. readline ( ) 读一行数据 .
. readlines ( ) 读出来的数据 , 以一行作为一个元素 , 放进列表里 .
1. 测试环境
手动创建一个文件写入写测试数据 , 文本文件换行符会占用一个字符的 , windows下使用 '\n' 作为换行符号 .
a . txt的内容 :
123
456
789
2. 判断是否具备可读功能
with open ( r'a.txt' , mode= 'r' , encoding= 'utf8' ) as f: print ( f. readable( ) )
3. 读取全部数据
with open ( r'a.txt' , mode= 'r' , encoding= 'utf8' ) as f: print ( ( f. read( ) , ) )
with open ( r'a.txt' , mode= 'r' , encoding= 'utf8' ) as f: print ( f. read( ) ) """123456789"""
4. 读取n个字符
with open ( r'a.txt' , mode= 'r' , encoding= 'utf8' ) as f: print ( ( f. read( 5 ) , ) )
with open ( r'a.txt' , mode= 'r' , encoding= 'utf8' ) as f: print ( f. read( 5 ) ) """1234"""
5. 读取一行数据
with open ( r'a.txt' , mode= 'r' , encoding= 'utf8' ) as f: t1 = ( f. readline( ) , f. readline( ) , f. readline( ) ) print ( t1) with open ( r'a.txt' , mode= 'r' , encoding= 'utf8' ) as f: print ( f. readline( ) ) print ( f. readline( ) ) print ( f. readline( ) ) """123456789""" with open ( r'a.txt' , mode= 'r' , encoding= 'utf8' ) as f: print ( f. readline( ) , end= '' ) print ( f. readline( ) , end= '' ) print ( f. readline( ) ) """123456789"""
6. 数据按行保存到列表
with open ( r'a.txt' , mode= 'r' , encoding= 'utf8' ) as f: print ( f. readlines( ) )
3.2 写系列
writable ( ) 判断文件对象是否用具备可写功能 , 返回一个布尔值 .
. write ( ) 写入数据 , 返回写入的字符个数 .
. writelines ( ) 写入多行数据 , 参数为列表套字符串的格式 , 字符串搭配 '\n' 换行 , 返回值永远为None .
. flush ( ) 强制将数据从内存缓存刷入到硬盘 , 默认在关闭文件前一步刷入硬盘中 , 返回值永远为None .
. fileno ( ) 返回文件描述符 , 系统每打开一个文件都有一个对应的描述符 .
1. 判断是否具备可写功能
with open ( r'a.txt' , mode= 'w' , encoding= 'utf8' ) as f: print ( f. writable( ) )
2. 写入数据
with open ( r'a.txt' , mode= 'w' , encoding= 'utf8' ) as f: print ( f. write( '你好!' ) )
3. 分批写入多行数据
with open ( r'a.txt' , mode= 'w' , encoding= 'utf8' ) as f: print ( f. write( 'abc\n' ) ) print ( f. write( 'def\n' ) ) print ( f. write( 'ghi' ) )
4. 批量写入多行数据
with open ( r'a.txt' , mode= 'w' , encoding= 'utf8' ) as f: f. writelines( [ '123\n' , '456\n' , '789' ] )
5. 将数据刷硬盘
wf = open ( 'a.txt' , 'w' , encoding= 'utf8' )
wf. write( '123' )
rf = open ( 'a.txt' , 'r' , encoding= 'utf8' )
print ( rf. read( ) )
wf = open ( 'a.txt' , 'w' , encoding= 'utf8' )
wf. write( '123' )
wf. flush( )
rf = open ( 'a.txt' , 'r' , encoding= 'utf8' )
print ( rf. read( ) )
6. 获取文件描述符
wf = open ( 'a.txt' , 'r' , encoding= 'utf8' )
print ( wf. fileno( ) )
rf = open ( 'a.txt' , 'r' , encoding= 'utf8' )
print ( rf. fileno( ) )
3.3 其它方法
. encoding ( ) 获取当前使用的字符编码 .
. name ( ) 获取文件的名称 .
. close ( ) 回收当前文件占用的系统资源 .
. closed ( ) 判断当前文件占用的系统资源是否回收 , 返回一个布尔值 .
f = open ( 'a.txt' , mode= 'rt' , encoding= 'utf-8' )
print ( f. encoding)
print ( f. name)
print ( f. closed)
f. close( )
print ( f. closed)
4. 文件指针移动
4.1 操作指针方法
. tell ( ) : 查看文件指针里文件开始处的偏移的位数 . . seek ( offset , whence ) : 设置指针离文件的起始位置间隔的 '字节数' .
参数介绍 :
offset : 偏移的字节数 , 整数向右→移动n位 , 负数向左←移动n位 . t模式使用utf8编码 , 中文占 3 个字节 , 英文占 1 个字节 .
whence : 设置指针的参考点 . t模式值只能设置为 0 , 参考点在文件开头 ( t模式下的默认设置 ) . b模式下值为 0 , 参考点在文件的开头 ( b模式下的默认设置 ) . b模式下值为 1 , 参考点设置为当前指针所在的位置 . b模式下值为 2 , 参考点在文件的末尾 .
4.2 t模式操作
with open ( r'a.txt' , mode= 'r+' , encoding= 'utf8' ) as f: print ( f. readable( ) ) print ( f. writable( ) ) print ( f. tell( ) ) f. write( '123456789' ) print ( f. tell( ) ) f. seek( 3 , 0 ) print ( f. tell( ) ) print ( f. read( ) )
4.3 b模式操作
with open ( r'a.txt' , mode= 'r+b' ) as f: print ( f. tell( ) ) f. write( '123456789' . encode( 'utf8' ) ) print ( f. tell( ) ) f. seek( - 3 , 2 ) print ( f. tell( ) ) f. seek( 1 , 1 ) print ( f. tell( ) ) res = f. read( ) print ( res) print ( res. decode( 'utf8' ) )
4.4 注意事项
在操作指针的时候不计算好位置 , 读取数据会报错 .
with open ( r'a.txt' , mode= 'r+' , encoding= 'utf8' ) as f: print ( f. write( '你好!' ) ) f. seek( 1 , 0 ) print ( f. read( ) )
with open ( r'a.txt' , mode= 'r+b' ) as f: print ( f. write( '你好!' . encode( 'utf8' ) ) ) f. seek( 1 , 0 ) print ( f. read( ) . decode( 'utf8' ) )
英 : UnicodeDecodeError : 'utf-8' codec can ' t decode byte 0xbd in position 0 :
invalid start byte . 中 : Unicode解码错误 : “utf- 8 ”编解码器无法解码位置 0 中的字节 0xbd :起始字节无效 .
5. 及时获取文件数据
程序 1 : 每过两秒往文件中写入一条数据 .
程序 2 : 一直获取文件的数据 , 获取到内容就打印 .
先运行程序 2 , 在运行程序 1.
from time import *
while True : with open ( r'a.log' , mode= 'at' , encoding= 'utf8' ) as f: sleep( 2 ) f. write( "%s 上海, 天气晴朗适宜出门. \n" % strftime( '%Y-%m-%d %H:%M:%S' ) )
with open ( r'a.log' , mode= 'rb' ) as f: f. seek( 0 , 2 ) while True : x = f. readline( ) if len ( x) != 0 : print ( x. decode( 'utf8' ) , end= '' )
6. 文件的复制
所有文件都是以二进制存储的 , 所有字节串模式可以打开任何类型的文件 .
字节串使用十六进制表示了八位二进制 .
FORM_PATH = r'C:\Users\13600\Desktop\a.txt'
TO_PATH = r'C:\Users\13600\Desktop\b.txt'
with open ( FORM_PATH, mode= 'rb' ) as f1, \open ( TO_PATH, mode= 'ab' ) as f2: res = f1. read( ) f2. write( res)
. read ( ) 会将文件中的所有数据都读取出来 , 如果文件很大 , 一次性读取 , 可能将内存占满 .
为了防止这种情况出现 , 可以使用for来遍历文件对象的数据 , 以行为单位分批复制 .
with open ( r'a.txt' , 'r' , encoding= 'utf-8' ) as f1, \open ( r'b.txt' , 'w' , encoding= 'utf-8' ) as f2: for line in f1: f2. write( line)
7. 文件修改模式
7.1 文件状态
数据是写在硬盘中 , 无法直接操作硬盘进行修改 .
需要先将数据读取到内存中 , 在内存中完成修改 , 在重新写入硬盘中 .
* 文件的插入模式是软件模拟出来的效果 .
硬盘中 , 文件有两种状态:
* 1. 占用态 : 文件占用的硬盘的空间不能写入数据的 .
* 2. 自由态 : 文件占用的硬盘的空间可以写入数据的 . 正常的文件都是占用态 , 当文件被删除的时候 , 文件的由占用态变成自由态 , 文件其实并没有真正的删除 ,
只是在目录下看不见它的存在 , 但是它还是存在硬盘当中 , 这个时候它占用的磁盘空间能被重新写入数据 ,
只有当其它文件占用完这些空间后 , 它才算真正的被删除 . ( 因此 , 硬盘中删除的文件是有几率被恢复的 ! )
7.2 硬盘占有率高
将a . txt源文件的内容加载到内置中进行修改 , 之后写入一个新的文件 . a . txt . ( . 开头的文件为隐藏文件 . )
在将原文件a . txt删除 , 将新文件 . a . txt重新命名a . txt .
import os
with open ( 'a.txt' , mode= 'rt' , encoding= 'utf8' ) as f1, \open ( '.a.txt' , mode= 'wt' , encoding= 'utf8' ) as f2: for i in f1: f2. write( i. replace( 'hello' , 'world' ) )
os. remove( 'a.txt' )
os. rename( '.a.txt' , 'a.txt' )
7.3 内存占有率高
将文件的全部数据存入一个变量中 , 在内存中修改完成后 , 清空文件 , 再将内存中的数据重新写入到文件中 .
with open ( r'a.txt' , mode= 'r' , encoding= 'utf8' ) as f: old_date = f. read( ) new_data = old_date. replace( 'hello' , 'word' )
with open ( r'a.txt' , mode= 'w+' , encoding= 'utf8' ) as f: f. write( new_data)
8. 可变字符串
import io
s = 'Hello World!'
s_io = io. StringIO( s)
print ( s_io)
print ( s_io. getvalue( ) , id ( s_io) )
print ( s_io. seek( 7 ) )
print ( s_io. write( 'O' ) )
print ( s_io. getvalue( ) , id ( s_io) )
print ( s_io. read( ) )
9. 练习
1. 编写文件copy工具 , 输入被拷贝文件的地址 , 输入拷贝到那个位置 , 即可运行 .
source_file = input ( '输入复制的文件路径>>>:' ) . strip( )
to_copy = input ( '输入拷贝到哪个路径>>>:' ) . strip( )
with open ( source_file, mode= 'rb' ) as f1, open ( to_copy, mode= 'wb' ) as f2: for i in f1: f2. write( i)
print ( '拷贝成功!' )
2. 编写登录程序 , 账号密码来自于文件 .
在当前目录下创建一个文件user_info . txt , 文件内容 :
kid | 123
with open ( 'user_info.txt' , mode= 'rt' , encoding= 'utf8' ) as f1: user_info = f1. read( )
print ( user_info)
name, pwd = user_info. split( '|' )
print ( name, pwd)
in_name = input ( '输入用户名称>>>:' ) . strip( )
in_pwd = input ( '输入用户密码>>>:' ) . strip( )
if in_name == name and in_pwd == pwd: print ( '登入成功!' )
else : print ( '用户名或密码错误!' )
3. 编写注册程序 , 账号密码来存入文件中 .
print ( '用户注册' . center( 30 , '-' ) )
in_name = input ( '输入用户名称>>>:' ) . strip( )
in_pwd = input ( '输入用户密码>>>:' ) . strip( )
user_info = '|' . join( [ in_name, in_pwd] ) + '\n'
print ( ( user_info, ) )
with open ( 'user_info.txt' , mode= 'at' , encoding= 'utf8' ) as f1: f1. write( user_info)
4. 编写用户登录接口 . 4.1 输入账号密码完成验证,验证通过后输出 "登录成功" , 结束程序 . 4.2 可以登录不同的用户 . 4.3 账号输入正确后 , 校验密码 , 密码错误提示密码错误 , 要求继续输入密码 . 密码累计输错三次锁定账户 , 关闭程序 . 锁定的用户存入文件中 , 这样才能保证程序下次运行时该用户仍然被锁定 . 4.4 账户名称输入错误提示用户按下 'q' 退出程序 , 否则进行下一轮登录 .
格式 :
用户名 | 密码 | 密码输入错误的次数 | 账户锁 | 换行符 .
user_info . txt文件的内容 :
aaa | 123 | 0 | False
bbb | 456 | 0 | False
ccc | 789 | 0 | False
( 这里有一个空行 )
def read_file ( ) : user_info_list = [ ] with open ( 'user_info.txt' , mode= 'rt' , encoding= 'utf8' ) as rf: for user_info in rf: user_info = user_info. split( '|' ) user_info_list. append( user_info) print ( f'用户信息: { user_info_list} ' ) return user_info_list
def write_file ( user_info, user_info_list) : user_info[ 2 ] = str ( int ( user_info[ 2 ] ) + 1 ) if int ( user_info[ 2 ] ) == 3 : user_info[ 3 ] = 'True' index = user_info_list. index( user_info) user_info_list[ index] = user_infowith open ( 'user_info.txt' , mode= 'wt' , encoding= 'utf8' ) as wf: for user_info in user_info_list: wf. write( '|' . join( user_info) ) return user_info
def main ( ) : while True : in_user = input ( '用户登入' . center( 30 , '-' ) + '\n输入用户名称>>>:' ) . strip( ) user_info_list = read_file( ) for user_info in user_info_list: if in_user == user_info[ 0 ] : if user_info[ 3 ] == 'True' : print ( '账户被锁定, 请联系管理员!' ) return while True : in_pwd = input ( '输入用户密码>>>:' ) . strip( ) if in_pwd == user_info[ 1 ] : print ( '登录成功!' ) return user_info = write_file( user_info, user_info_list) if user_info[ 3 ] == 'True' : print ( '多次输入密码错误, 账户以被锁定, 请联系管理员!' ) return print ( '输入密码错误, 请重新' , end= '' ) else : if input ( '你输入的账户名不存在, 按下"q"退出, 否则继续>>>:' ) == 'q' : return
main( )
5. 为上例程序添加注册功能 , 运行程序后可选 '注册' 与 '登入' .
def read_file ( ) : user_info_list = [ ] with open ( 'user_info.txt' , mode= 'rt' , encoding= 'utf8' ) as rf: for user_info in rf: user_info = user_info. split( '|' ) user_info_list. append( user_info) print ( f'用户信息: { user_info_list} ' ) return user_info_list
def update ( user_info, user_info_list) : user_info[ 2 ] = str ( int ( user_info[ 2 ] ) + 1 ) if int ( user_info[ 2 ] ) == 3 : user_info[ 3 ] = 'True' index = user_info_list. index( user_info) user_info_list[ index] = user_inforeturn user_info, user_info_list
def write_file ( user_info_list) : with open ( 'user_info.txt' , mode= 'wt' , encoding= 'utf8' ) as wf: for user_info in user_info_list: wf. write( '|' . join( user_info) )
def login ( ) : while True : in_user = input ( '用户登入' . center( 30 , '-' ) + '\n输入用户名称>>>:' ) . strip( ) user_info_list = read_file( ) for user_info in user_info_list: if in_user == user_info[ 0 ] : if user_info[ 3 ] == 'True' : print ( '账户被锁定, 请联系管理员!' ) return while True : in_pwd = input ( '输入用户密码>>>:' ) . strip( ) if in_pwd == user_info[ 1 ] : print ( '登录成功!' ) return user_info, user_info_list = update( user_info, user_info_list) write_file( user_info_list) if user_info[ 3 ] == 'True' : print ( '多次输入密码错误, 账户以被锁定, 请联系管理员!' ) return print ( '输入密码错误, 请重新' , end= '' ) else : if input ( '你输入的账户名不存在, 按下"q"退出, 否则继续>>>:' ) == 'q' : return
def register ( ) : user_name_list = [ ] print ( '用户注册' . center( 30 , '-' ) ) while True : name = input ( '输入用户名称>>>:' ) . strip( ) user_info_list = read_file( ) for user_info in user_info_list: user_name_list. append( user_info[ 0 ] ) if name in user_name_list: print ( '用户名称已经存在, 请重新' , end= '' ) continue pwd = input ( '输入用户密码>>>:' ) . strip( ) user_info = [ name, pwd, '0' , 'False' , '\n' ] user_info_list. append( user_info) write_file( user_info_list) if input ( '用户注册成功, 输入q返回主界面, 否则继续注册>>>:' ) . strip( ) == 'q' : return
def sign_out ( ) : import syssys. exit( )
def main ( ) : while True : func_dic = { '' : [ '\b-' + '功能选择' . center( 30 , '-' ) ] , '0' : [ '注册功能' , register] , '1' : [ '登录功能' , login] , '2' : [ '退出程序' , sign_out] } for k, v in func_dic. items( ) : print ( k, v[ 0 ] ) func_num = input ( '输入对应功能序号>>>:' ) . strip( ) if not func_num. isdigit( ) : print ( '输入的序号不正确, 请重新' , end= '' ) continue if func_num not in func_dic. keys( ) : print ( '输入的序号不存在, 请重新' , end= '' ) continue func_dic[ func_num] [ 1 ] ( )
main( )