6.1 Python 文件类型及常用内置方法

文章目录

      • 1. 文件读写
        • 1.1 文件
        • 1.2 open函数
          • 1. file参数
          • 2. mode参数
          • 3. encoding参数
        • 1.3 操作文件注意事项
          • 1. 操作文件原理
          • 2. 操作文件步骤
          • 3. 回收系统资源
        • 1.4 上下文管理
      • 2. 模式测试
        • 2.1 只写模式
          • 1. 文件不存在
          • 2. 文件存在
        • 2.2 读模式
          • 1. 路径存在
          • 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()方法回收系统占用的空间.
# 执行程序之后再当前目录生成两个文本文件.# 在当前目录下创建一个文件, 名为a.txt.
file1 = open('a.txt', mode='w')# 返回一个文本IO包装, 名字为a.txt, 模式为w模式,
# 默认使用使用gbk编码(cp936编码-->IBM发明代码页时, gbk在代码页的第936).
print(file1)  # <_io.TextIOWrapper name='a.txt' mode='w' encoding='cp936'># 使用文件对象的方法操作文件...# 操作完成后, 回收文件占用的计算机资源.
file1.close()# 在当前目录下创建一个文件, 名为b.txt, 设置编码为utf8.
file2 = open('b.txt', mode='w', encoding='utf8')# 返回一个文本IO包装, 名字为a.txt, 模式为w模式, 使用
print(file2)  # <_io.TextIOWrapper name='b.txt' mode='w' encoding='utf8'># 使用文件对象的方法操作文件...# 操作完成后, 回收文件占用的计算机资源.
file2.close()# 关闭文件之后, 就不能通过文件对象操作文件了.
file2.write('123')
# 往文件内写入信息, 报错:
# 英: ValueError: I/O operation on closed file.
# 中: 值错误: 对关闭的文件执行IO操作.
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 += 1print(f'打开文件的个数:{count}')
在打开一定数量的文件后, 文件打开操作就失败了. (文件资源泄漏)
计算机是使用二进制来表示数据的, 因此计算机里的很多数据都是按照2的多少次方这样的方式来表示的,
默认可打开 8189 + 3 = 8192 => 213次方个文件.
每一个程序启动的时候, 都会默认打开一下三个文件, 对应描述符0, 1, 2(其它描述符从3开始):
标准输入: 键盘, input()通过标准输入来读数据.
标准输出: 显示器, print()往标准输出文件里写数据.
标准错误: 显示器.
这三个文件很特殊, 这三个文件不是保存在磁盘里, 而是在键盘, 显示器当中的.文件资源泄漏, 是很重要的问题, 这个问题不会第一时间报错出来, 在比较大的程序中, 这问题很难发现,
当程序报错的时候, 不是在我们写的那一时间报错, 可能会在后面的时候发生文件资源泄漏,
这时候就不容易找出这个问题.

2023-02-18_01715

不用列表来存储文件句柄的时候, 打开的文件就不止8189个了, 这个时候变量绑定新打开的文件,
没有被使用的文件会自动关闭回收系统资源, 真正打开的文件始终只有一个.

2023-02-16_01706

1.4 上下文管理
with 关键字: 上下文管理, 打开文件使用完毕后, 会自动关闭文件回收系统资源.
with 可以同时打开多个文件, 同时打开一个文件会出现文件错乱的情况.使用格式:
with open(r'文件路径', 读写模式, 字符编码) as 文件句柄:子代码块打开多个文件格式:
with open() as 文件句柄1, open() as 文件句柄2:子代码块* 读写操作必须在with语句的子代码块内操作, 缩进结束也就意味着关闭文件, 回收资源.

2. 模式测试

读写文件的时候有一个文件指针的概念, 它表示着当前操作所在的位置.
打开文件时文件指针默认在开头, 读写数据时文件指针会向后移动, 读写完闭之后, 文件指针就到末尾了. 

GIF 2023-2-16 20-48-53

2.1 只写模式
只写模式: 文件不存在被创建, 存在数据被清空.
f.write('字符串'): 往文件写入数据, 返回写入的字符个数, 需要换行时, 使用换行的转义字符'\n'.
1. 文件不存在
# 在当前目录新建a.txt文件.
with open(r"a.txt", mode='w', encoding='utf-8') as f1:# 往文件中写入字符串'123', 并打印.write方法的返回值.print(f1.write('123'))  # 3

image-20230216201213532

2023-02-16_01707

2. 文件存在
# 使用w模式打开已存在的文件, 会将文件的内容清空.
with open(r"a.txt", mode='w', encoding='utf-8') as f1:pass

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2.2 读模式
只读模式: 文件不存在报错, 文件存在则打开.
f.read(): 读取文件全部数据.
f.read(n): 读取n个字符.
1. 路径存在
# 往a.txt写入'你好!'.
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# 英: FileNotFoundError: [Errno 2] No such file or directory: 'c.txt'
# 中: 找不到文件错误:[Errno 2]没有这样的文件或目录:“c.txt”.
2.3 追加模式
追加模式: 文件不存在则创建, 文件存在则从文件的末尾追加数据.
文件指针会移动到在文件末尾, 新内容永远在文件的末尾开始追加.
with open(r"d.txt", mode='a', encoding='utf-8') as f1:# 追加信息.print(f1.write('123'))  # 3print(f1.write('456'))  # 3with open(r"d.txt", mode='r', encoding='utf-8') as f2:print(f2.read())  # 123456
2.4 字节串模式
# a.txt的文件内容: 你好!
# 以字节串为单位读取所有数据.
with open(r'a.txt', mode='rb') as f:# 读取所有的数据.res = f.read()print(res)    # b'\xe4\xbd\xa0\xe5\xa5\xbd!'# 将字节串转为字符串, a.txt是以utf8编码存储的.print(res.decode('utf8'))
2.5 附加模式
附加模式:
r模式搭配'+号': 让读模式具备w模式的功能, 每写入一个字符覆盖之前存在的一个字符, 写入的数据比原有的数据少, 会遗留原来的数据.
w模式搭配'+号': 让写模式具备w模式的功能, 会先清空在写入.
# r模式不能使用write()方法, 否则会报错.
with open('a.txt', 'r', encoding='utf8') as f:f.write('你好!')# 英: io.UnsupportedOperation: not writable
# 中 io.不支持的操作:不可写
# w模式不能使用read()方法, 否则会报错.
with open('a.txt', 'w', encoding='utf8') as f:f.read()# 英: io.UnsupportedOperation: not readable
# 中 io.不支持的操作:不可读
1. 让只读模式具备可写功能
# 让r只读模式具备可写能力.
with open('a.txt', 'r+', encoding='utf8') as f:f.write('你好!')# 文件的文件指针现在在末尾, 它的后面也没有数据, 这个时候不能直接使用.read()方法读取文件得到空.# 后面会学习操作文件指针怎么移动...print(f.read())

image-20230218104737608

2. 覆盖模式
# 让r只读模式具备可写能力.
with open('a.txt', 'r+', encoding='utf8') as f:f.write('123456789')with open('a.txt', 'r+', encoding='utf8') as f:f.write('abc')

2023-02-19_01717

3. 让只写模式具备可读功能
# 让w只读模式具备可读能力.
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())  # True
3. 读取全部数据
# 字符串最为容器类型的元素时, 转义字符不会生效.
with open(r'a.txt', mode='r', encoding='utf8') as f:# 读取全部数据.print((f.read(), ))  # ('123\n456\n789',)# 打印字符串时, 转义符号会生效.
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:# 读取n个字符.print((f.read(5), ))  # ('123\n4',)# 打印字符串时, 转义符号会生效.
with open(r'a.txt', mode='r', encoding='utf8') as f:# 读取n个字符.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)  # ('123\n', '456\n', '789')with open(r'a.txt', mode='r', encoding='utf8') as f:# 一次读取一行, 打印字符串时, 转义符号会生效.print(f.readline())  # 打印 123 + 换行.print(f.readline())  # 打印 456 + 换行.print(f.readline())  # 打印 789 这里结束了没有换行符号."""123456789"""# 因为print()函数执行结束也会有一个换行符号, 第一次和第二次执行print()等于有两个换行符号.with open(r'a.txt', mode='r', encoding='utf8') as f:# 一次读取一行, 打印字符串时, 转义符号会生效.print(f.readline(), end='')  # 取消print的换行.print(f.readline(), end='')  # 取消print的换行.print(f.readline())"""123456789"""
6. 数据按行保存到列表
with open(r'a.txt', mode='r', encoding='utf8') as f:# 读取全部数据, 以行为元素保存到列表中.print(f.readlines())  # ['123\n', '456\n', '789']
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())  # True
2. 写入数据
with open(r'a.txt', mode='w', encoding='utf8') as f:# 返回写入的字符个数.print(f.write('你好!'))  # 3
3. 分批写入多行数据
with open(r'a.txt', mode='w', encoding='utf8') as f:# 分批写入多行, 在末尾加上'\n'换行符号, 占用一个字符.print(f.write('abc\n'))  # 4print(f.write('def\n'))  # 4print(f.write('ghi'))  # 3

image-20230218133151272

4. 批量写入多行数据
with open(r'a.txt', mode='w', encoding='utf8') as f:# 一次写入多行数据, 参数是列表套字符串格式, 在字符串末尾搭配'\n'换行.f.writelines(['123\n', '456\n', '789'])

image-20230218133906531

5. 将数据刷硬盘
# 写入数据
wf = open('a.txt', 'w', encoding='utf8')
wf.write('123')# 读取数据, 这个时候数据还没有被刷入硬盘中, 在程序结束回收资源前才刷入到硬盘.
rf = open('a.txt', 'r', encoding='utf8')
print(rf.read())

image-20230218135147267

# 写入数据.
wf = open('a.txt', 'w', encoding='utf8')
wf.write('123')
# 将数据刷入硬盘.
wf.flush()# 读取数据.
rf = open('a.txt', 'r', encoding='utf8')
print(rf.read())  # 123

image-20230218135730787

6. 获取文件描述符
# 获取文件描述符.
wf = open('a.txt', 'r', encoding='utf8')
print(wf.fileno())  # 3# 获取文件描述符.
rf = open('a.txt', 'r', encoding='utf8')
print(rf.fileno())  # 4
3.3 其它方法
.encoding()  获取当前使用的字符编码.
.name()      获取文件的名称.
.close()     回收当前文件占用的系统资源.
.closed()    判断当前文件占用的系统资源是否回收, 返回一个布尔值.
f = open('a.txt', mode='rt', encoding='utf-8')
# 获取当前使用的字符编码.
print(f.encoding)  # utf-8
# 获取文件的名称.
print(f.name)  # a.txt
# 判断当前文件占用的系统资源是否回收.
print(f.closed)  # False
# 回收当前文件占用的系统资源.
f.close()
# 判断当前文件占用的系统资源是否回收.
print(f.closed)  # True

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模式操作
# r+ 可读可写模式.
with open(r'a.txt', mode='r+', encoding='utf8') as f:# 判断文件对象是否具备可读能力.print(f.readable())  # True# 判断文件对象是否具备可写能力.print(f.writable())  # True# 查看指针当前所在的位置.print(f.tell())  # 0# 写入9位数, 1~9.f.write('123456789')# 查看指针当前所在的位置.print(f.tell())  # 9# 将指针设置到开头, 并向右移动三个字节.f.seek(3, 0)# 查看指针当前所在的位置.print(f.tell())  # 3# 读取文件的数据, 指针向后移动, 指针后面的数据才能被读取到!print(f.read())  # 456789
4.3 b模式操作
# r+ 覆盖模式.
with open(r'a.txt', mode='r+b') as f:# 查看指针当前所在的位置.print(f.tell())  # 0# 将字符串按utf8编程成字节串格式写入到文件中.f.write('123456789'.encode('utf8'))# 查看指针当前所在的位置.print(f.tell())  # 9# 将指针参考点设置到末尾, 向左移动三个字节.f.seek(-3, 2)# 查看指针当前所在的位置.print(f.tell())  # 9# 将当前位置设置为指针参考点, 向右移动一位.f.seek(1, 1)print(f.tell())  # 7# 读取数据.res = f.read()# 打印字节串格式数据.print(res)  # b'89'# 打印字符串格式数据.print(res.decode('utf8'))  # 89
4.4 注意事项
在操作指针的时候不计算好位置, 读取数据会报错.
# r+ 可读可写模式.
with open(r'a.txt', mode='r+', encoding='utf8') as f:# 写入三个字符.print(f.write('你好!'))  # 3# 向右便宜一位字节, 获取文本数据.f.seek(1, 0)print(f.read())  # 报错↓
with open(r'a.txt', mode='r+b') as f:# 将字符串按utf8编程成字节串格式写入到文件中.print(f.write('你好!'.encode('utf8')))  # 7, 返回写入的字节个数.# 指针向右偏移一位, 在读取文件数据.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)# strftime('%Y-%m-%d %H:%M:%S') 获取当前时间.f.write("%s 上海, 天气晴朗适宜出门. \n" % strftime('%Y-%m-%d %H:%M:%S'))# 2023-02-19 04:15:01 上海, 天气晴朗适宜出门.
# 只读模式打开文件, 以字节为单位读取文件.
with open(r'a.log', mode='rb') as f:# 将文件指针设置到文本的末尾, 这样设置的目的就是不读取前面存在的数据了, 将要读取新写入的内容.f.seek(0, 2)while True:# 读取一行数据.x = f.readline()# 判断是否读取到了数据, 读取到了数据将字节串转为字符串, 没有读取到数据进行下一轮读取...if len(x) != 0:# 获取的字符串后面有'\n'换行, 那么print的换行就可以关闭了, 否则会出现一行空白行.print(x.decode('utf8'), end='')# 2023-02-19 04:15:01 上海, 天气晴朗适宜出门.

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.
# os模块是Python对操作系统操作接口的封装.
import os# 文件句柄1为只读模式, 文件句柄2为只写模式.
with open('a.txt', mode='rt', encoding='utf8') as f1, \open('.a.txt', mode='wt', encoding='utf8') as f2:# 遍历a.txt文件信息, 写入到.a.txt.for i in f1:  # 将字符串中的hello替换成world.f2.write(i.replace('hello', 'world'))# 移除源文件.
os.remove('a.txt')  # os.remove('文件夹'), 将当前目录下的a.txt删除.
# 修改文件名称.
os.rename('.a.txt', 'a.txt')  # os.rename('被修改名称的文件名', '文件新名称')
7.3 内存占有率高
将文件的全部数据存入一个变量中, 在内存中修改完成后, 清空文件, 再将内存中的数据重新写入到文件中.
# 将所有的数据保存到变量中, 文件太大会会导致内存溢出.
with open(r'a.txt', mode='r', encoding='utf8') as f:old_date = f.read()# 将字符串中的hello替换成world.new_data = old_date.replace('hello', 'word')# 将内容修改完成后, 清空文件的数据, 将新的数据写入文件中.
with open(r'a.txt', mode='w+', encoding='utf8') as f:f.write(new_data)

8. 可变字符串

# 导入io模块.
import io# 定义一个字符串
s = 'Hello World!'
# 实例化得到一个StringIO对象.
s_io = io.StringIO(s)
# 查看对象.
print(s_io)  # <_io.StringIO object at 0x0000020DD795E0D0># 获取对象的值.
print(s_io.getvalue(), id(s_io))  # Hello World!  2334830360320# 移动指针.
print(s_io.seek(7))  # 7
# 修改指针所在位置的数据.
print(s_io.write('O'))  # 1
print(s_io.getvalue(), id(s_io))  # Hello WOrld!  2334830360320# 获取指针后面的所有数据!
print(s_io.read())  # rld!

9. 练习

1. 编写文件copy工具, 输入被拷贝文件的地址, 输入拷贝到那个位置, 即可运行.
# 输入源文件的路径, str.strip()移除前后末空白字符.
source_file = input('输入复制的文件路径>>>:').strip()  # 
# 输入复制的文件路径>>>:C:\Users\13600\Desktop\1.txt# 拷贝到何处.
to_copy = input('输入拷贝到哪个路径>>>:').strip()
# 输入拷贝到哪个路径>>>:C:\Users\13600\Desktop\2.txt# 遍历文件对象进行文件的拷贝工作.
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)  # kid|123# 按'|'切分, 得到一个列表, 再解包赋值给变量 name, pwd.
name, pwd = user_info.split('|')
print(name, pwd)  # kid 123# 获取用户输入信息.
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()# 组织字符串的格式, 一个用户信息占用一行, 在字符串的末尾加上换行符\n.
user_info = '|'.join([in_name, in_pwd]) + '\n'# 查下写入的原生字符串, 字符串作为容器对象的元素, 转义字符不会生效.
print((user_info, ))  # ('kid|123\n',)# 以追加模式写入文件.
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
(这里有一个空行)
# 2. 读取文件数据, 并文件数据每一行用户信息转为列表的元素.
def read_file():# 2.1 定义一个列表, 存储所有用户的信息.user_info_list = []# 2.2 读取文件信息.with open('user_info.txt', mode='rt', encoding='utf8') as rf:# 2.2.1 按行读取文件信息.for user_info in rf:# 2.2.1 字符串去除末尾的换行符号, 再按'|'切分. 将处理好的数据添加到列表中.user_info = user_info.split('|')# 'aaa|123|0|False\n' --> ['aaa', '123', '0', 'False', '\n']# 'bbb|456|0|False\n' --> ['bbb', '456', '0', 'False', '\n']# 'ccc|789|0|False\n' --> ['ccc', '789', '0', 'False', '\n']# 2.2.2 将用户信息添加到大列表中.user_info_list.append(user_info)# 2.3 打印所有用户信息.print(f'用户信息: {user_info_list}')# [['aaa', '123', '0', 'False', '\n'], ['bbb', '456', '0', 'False', '\n'], ...]# 2.4 将所有用户信息返回.return user_info_list# 3. 更新文件数据, 将更新后的列表套字符串格式数据按行写入文件.
def write_file(user_info, user_info_list):# 3.1 更新密码错误次数.user_info[2] = str(int(user_info[2]) + 1)# 3.2 当密码错误三次后锁定账户.if int(user_info[2]) == 3:# 3.2.1 更改账户锁定状态.user_info[3] = 'True'# 3.3 获取当前用户信息为大列表中的第几个元素.index = user_info_list.index(user_info)# 3.4 更新大列表中用户信息.user_info_list[index] = user_info# 3.5 将所有的用户信息更新到文件.with open('user_info.txt', mode='wt', encoding='utf8') as wf:# 3.5.1 遍历用户信息列表.for user_info in user_info_list:# .1 将列表内的字符串拼成 'x|p|0|False\n' 格式写入到文件中.wf.write('|'.join(user_info))# 3.6 将当前账户的信息返回, 后续需要需要用户信息的错误输入错误次数.return user_info# 1. 主函数
def main():# 1.1 循环校验用户名称.while True:# 1.1.1 获取用户名称(字符串格式).in_user = input('用户登入'.center(30, '-') + '\n输入用户名称>>>:').strip()# 1.1.2 从文件中获取用户信息列表. (看序号2.)user_info_list = read_file()# 1.1.3 从列表中遍历用户信息, 逐一校验用户名是否存在.for user_info in user_info_list:# .1 校验用户名称是否存在(str == str).if in_user == user_info[0]:# .11 用户名存在, 先判断用户账户是否被锁, 被锁定直接结束程序.if user_info[3] == 'True':# .111 账户被锁定提示信息.print('账户被锁定, 请联系管理员!')# .112 结束函数.return# .12 循环校验用户密码.while True:# .121 获取用户密码(字符串格式).in_pwd = input('输入用户密码>>>:').strip()# .122 校验密码(str == str), 校验成功则退出.if in_pwd == user_info[1]:# ..1 登入提示信息.print('登录成功!')# ..2 结束函数.return# .123 密码输入错误, 将错误的次数更新到文件中, 接收更新的用户信息. (看序号3)user_info = write_file(user_info, user_info_list)# .124 用户被锁定则提示, 并退出程序.if user_info[3] == 'True':# ..1print('多次输入密码错误, 账户以被锁定, 请联系管理员!')# ..2return# .125 用户没有被锁定, 则说明密码错误不够三次, 进入下一轮循环.print('输入密码错误, 请重新', end='')# 1.1.4 for循环正常结束说明账户不存在.else:# .1 按下q继续输入账户名进行下一轮校验.if input('你输入的账户名不存在, 按下"q"退出, 否则继续>>>:') == 'q':# .11 结束程序.return# 0. 程序入口.
main()
5. 为上例程序添加注册功能, 运行程序后可选'注册''登入'.
# 2. 读取文件数据, 并文件数据每一行用户信息转为列表的元素.
def read_file():# 2.1 定义一个列表, 存储所有用户的信息.user_info_list = []# 2.2 读取文件信息.with open('user_info.txt', mode='rt', encoding='utf8') as rf:# 2.2.1 按行读取文件信息.for user_info in rf:# 2.2.1 字符串去除末尾的换行符号, 再按'|'切分. 将处理好的数据添加到列表中.user_info = user_info.split('|')# 'aaa|123|0|False\n' --> ['aaa', '123', '0', 'False', '\n']# 'bbb|456|0|False\n' --> ['bbb', '456', '0', 'False', '\n']# 'ccc|789|0|False\n' --> ['ccc', '789', '0', 'False', '\n']# 2.2.2 将用户信息添加到大列表中.user_info_list.append(user_info)# 2.3 打印所有用户信息.print(f'用户信息: {user_info_list}')# [['aaa', '123', '0', 'False', '\n'], ['bbb', '456', '0', 'False', '\n'], ...]# 2.4 将所有用户信息返回.return user_info_list# 5. 更新数据函
def update(user_info, user_info_list):# 5.1 更新密码错误次数.user_info[2] = str(int(user_info[2]) + 1)# 5.2 当密码错误三次后锁定账户.if int(user_info[2]) == 3:# 5.2.1 更改账户锁定状态.user_info[3] = 'True'# 5.3 获取当前用户信息为大列表中的第几个元素.index = user_info_list.index(user_info)# 5.4 更新大列表中用户信息.user_info_list[index] = user_info# 5.6 将当前账户的信息返回, 后续需要需要用户信息的错误输入错误次数.return user_info, user_info_list# 3. 更新文件数据, 将更新后的列表套字符串格式数据按行写入文件.
def write_file(user_info_list):# 3.1 将所有的用户信息更新到文件.with open('user_info.txt', mode='wt', encoding='utf8') as wf:# 3.1.1 遍历用户信息列表.for user_info in user_info_list:# .1 将列表内的字符串拼成 'x|p|0|False\n' 格式写入到文件中.wf.write('|'.join(user_info))# 4. 登录函数
def login():# 4.1 循环校验用户名称.while True:# 4.1.1 获取用户名称(字符串格式).in_user = input('用户登入'.center(30, '-') + '\n输入用户名称>>>:').strip()# 4.1.2 从文件中获取用户信息列表. (看序号2.)user_info_list = read_file()# 4.1.3 从列表中遍历用户信息, 逐一校验用户名是否存在.for user_info in user_info_list:# .1 校验用户名称是否存在(str == str).if in_user == user_info[0]:# .11 用户名存在, 先判断用户账户是否被锁, 被锁定直接结束程序.if user_info[3] == 'True':# .111 账户被锁定提示信息.print('账户被锁定, 请联系管理员!')# .112 结束函数.return# .12 循环校验用户密码.while True:# .121 获取用户密码(字符串格式).in_pwd = input('输入用户密码>>>:').strip()# .122 校验密码(str == str), 校验成功则退出.if in_pwd == user_info[1]:# ..1 登入提示信息.print('登录成功!')# ..2 结束函数.return# .123 密码输入错误, 将错误的次数更新到文件中, 接收更新的用户信息. (看序号3)# 更新数据user_info, user_info_list = update(user_info, user_info_list)write_file(user_info_list)# .124 用户被锁定则提示, 并退出程序.if user_info[3] == 'True':# ..1print('多次输入密码错误, 账户以被锁定, 请联系管理员!')# ..2return# .125 用户没有被锁定, 则说明密码错误不够三次, 进入下一轮循环.print('输入密码错误, 请重新', end='')# 4.1.4 for循环正常结束说明账户不存在.else:# .1 按下q继续输入账户名进行下一轮校验.if input('你输入的账户名不存在, 按下"q"退出, 否则继续>>>:') == 'q':# .11 结束程序.return# 2. 账户注册.
def register():# 2.1 用户名称列表.user_name_list = []# 2.2 提示.print('用户注册'.center(30, '-'))# 2.3 循环注册.while True:# 2.3.1 获取用户名称.name = input('输入用户名称>>>:').strip()# 2.3.2 读取文件, 判断用户是否已经存在.user_info_list = read_file()# 2.3.3 获取所有的用户名字.for user_info in user_info_list:# 将用户名称添加到一个列表中.user_name_list.append(user_info[0])# 2.3.4 用户名称已经存在, 提示从新取一个名字.if name in user_name_list:print('用户名称已经存在, 请重新', end='')continue# 2.3.5 输入密码.pwd = input('输入用户密码>>>:').strip()# 2.3.6 组织格式用户数据格式user_info = [name, pwd, '0', 'False', '\n']# 2.3.7 将用户信息更新到大列表中.user_info_list.append(user_info)# 2.3.8 更新数据到文件中.write_file(user_info_list)# 2.3.9 提示注册成功, 询问下一步操作.if input('用户注册成功, 输入q返回主界面, 否则继续注册>>>:').strip() == 'q':# 结束注册程序, 返回主界面.return# 6. 退出程序.
def sign_out():# 6.1 导入sys模块.import sys# 6.2 结束程序运行.sys.exit()# 1. 主函数.
def main():# 1.1 主界面循环.while True:# 1.1.1 定义功能字典.func_dic = {# 打印的时候会有一个空格, 让\b覆盖掉.  str.center()是以这个字符串中心左右填充'-', 所有使用+号拼接.'': ['\b-' + '功能选择'.center(30, '-')],'0': ['注册功能', register],'1': ['登录功能', login],'2': ['退出程序', sign_out]}# 1.1.2 打印功能提示.for k, v in func_dic.items():print(k, v[0])# 1.1.3 获取功能序号.func_num = input('输入对应功能序号>>>:').strip()# 1.1.4 判断序号是否为纯数字字符串.if not func_num.isdigit():# .1 如果不是, 表明输入的序号不正确, 请重新输入.print('输入的序号不正确, 请重新', end='')continue# 1.1.5 判断序号是否存在.if func_num not in func_dic.keys():# .1 序号不存在, 要求用户重新输入.print('输入的序号不存在, 请重新', end='')continue# 1.1.6 序号存在, 通过输入的键获取值, 调用函数.func_dic[func_num][1]()# 0. 程序入口
main()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/28831.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

​1:25万基础电子地图(江西版)

我们在《50幅1:25万基础电子地图&#xff08;四川版&#xff09;》和《1&#xff1a;25基础电子地图&#xff08;云南版&#xff09;》等文中&#xff0c;为你分享过四川和云南的基础电子地图。 现在我们再为你分享江西的1&#xff1a;25万基础电子地图&#xff0c;你可以在文…

第9章 类

第9章 类 9.1 创建和使用类9.1.1 创建 Dog 类9.1.2 根据类创建实例 9.2 使用类和实例9.2.1 Car 类9.2.2 给属性指定默认值9.2.3 修改属性的值 9.3 继承9.3.1 子类的方法__init__()9.3.2 给子类定义属性和方法9.3.3 重写父类的方法9.3.4 将实例用作属性9.3.5 模拟实物 9.4 导入类…

【AI绘画】文心一格

本人详解 作者:王文峰,参加过 CSDN 2020年度博客之星,《Java王大师王天师》 公众号:JAVA开发王大师,专注于天道酬勤的 Java 开发问题中国国学、传统文化和代码爱好者的程序人生,期待你的关注和支持!本人外号:神秘小峯 山峯 转载说明:务必注明来源(注明:作者:王文峰…

数据结构-绪论

目录 前言一、从问题到程序二、数据结构的研究内容三、理解数据结构3.1 数据3.2 结构3.2.1 逻辑结构的分类3.2.2 存储结构的分类 3.3 数据结构 总结 前言 本篇文章先介绍数据结构的研究内容&#xff0c;然后再介绍如何去理解数据结构&#xff0c;着重介绍表示数据结构关系的逻…

springboot与flowable(5):任务分配(表达式)

在做流程定义时我们需要给相关的用户节点指派对应的处理人。在flowable中提供了三种分配的方式。 一、固定分配 在分配用户时选择固定值选项确认即可。 二、表达式 1、值表达式 2、方法表达式 三、表达式流程图测试 1、导出并部署 导出流程图&#xff0c;复制到项目中 部署流…

机器学习——集成学习和梯度提升决策树

集成学习 不同的算法都可以对解决同一个问题&#xff0c;但是可能准确率不同&#xff0c;集成学习就是不同算法按照某种组合来解决问题&#xff0c;使得准确率提升。 那怎么组合算法呢&#xff1f; 自举聚合算法**&#xff08;bagging&#xff09;** 顾名思义是 自举聚合 自举…

怎么做成的文件二维码?扫阅览文件的制作方法

现在用二维码来分享或者查看文件是一种很常用的方式&#xff0c;比如常见的文件内容有简历、资料、作品、压缩包等等。通过将文件生成二维码能够在提升文件传输速度的同时还有利于用户体验的提升&#xff0c;那么如何制作可以长期提供文件预览或者下载的二维码呢&#xff1f; …

【Redis实战篇】redis的擅长实现的功能

&#x1f525;作者主页&#xff1a;小林同学的学习笔录 &#x1f525;小林同学的专栏&#xff1a;JAVA之基础专栏 【Redis实战篇】Redis有可能出现的问题以及如何解决问题_redis实现用户登录可能造成哪些问题-CSDN博客 本文接上面的文章 目录 2.优惠券秒杀 2.1 全局唯一ID 2.…

新办理北京广播电视节目制作许可证需要什么条件

在北京想要从事广播电视节目制作&#xff0c;那就需要企业拥有广播电视节目制作经营许可证。此许可证不仅是企业合法经营的基础&#xff0c;同时也是保障节目制作质量和内容合规的标志。如何办理&#xff0c;详情致电咨询我或者来公司面谈。 北京广播电视节目制作经营许可证申请…

访问jlesage/firefox镜像创建的容器中文乱码问题

目录 介绍总结 介绍 最近在使用jlesage/firefox镜像创建容器的时候&#xff0c;发现远程管理家里网络的时候中文会出现乱码&#xff0c;导致整个体验非常的不好&#xff0c;网上查找资料说只要设置环境变量ENABLE_CJK_FONT1 就可以解决问题&#xff0c;抱着试一试的态度还真的成…

「网络原理」IP 协议

&#x1f387;个人主页&#xff1a;Ice_Sugar_7 &#x1f387;所属专栏&#xff1a;计网 &#x1f387;欢迎点赞收藏加关注哦&#xff01; IP 协议 &#x1f349;报头结构&#x1f349;地址管理&#x1f34c;动态分配 IP 地址&#x1f34c;NAT 机制&#xff08;网络地址映射&am…

示例:WPF中应用DataGrid读取实体DisplayAttribute特性自动自动生成列名

一、目的&#xff1a;通过重写DataGrid的OnAutoGeneratingColumn方法实现根据定义特性自动生成列头信息功能 二、实现 <DataGrid ItemsSource"{local:GetStudents Count50}"/>实体定义如下 public class Student{[DataGridColumn("*")][Display(Na…

iOS18那些隐藏有趣的新功能分享!

WWDC 2024开幕式结束后&#xff0c;苹果迅速向开发者推送了iOS 18的首个测试版更新。很多果粉和小编一样&#xff0c;第一时间进行了升级。 自定义应用图标位置和颜色、应用锁、隐藏图标、全新控制中心、新增密码应用以及照片重新排版等新功能都表现出色。这些明面上的新功能大…

网络安全等级保护制度详解,一文掌握核心要点!

一、等级保护制度发展情况 等级保护制度的法律依据 《计算机信息系统安全保护条例》&#xff08;1994年General Office of the State Council第147号令&#xff09; 公安部主管全国计算机信息系统安全保护工作。 计算机信息系统实行安全等级保护&#xff0c;安全等级的划分…

目录文件管理

文章目录 Linux目录结构树形目录结构根目录常见的子目录子目录的作用 查看及检索文件查看文件内容cat格式 more格式操作方法 less格式操作方法 head格式 tail格式 统计文件内容wc格式选项 检索和过滤文件内容grep格式选项查找条件 备份及恢复文档压缩命令gzip bzip2格式压缩解压…

Redis 网络模型

一、用户空间和内核空间 1.1 linux 简介 服务器大多采用 Linux 系统&#xff0c;这里我们以 Linux 为例来讲解&#xff0c;下面有两个不同的 linux 发行版&#xff0c;分别位 ubuntu 和 centos&#xff0c;其实发行版就是在 Linux 系统上包了一层壳。 任何 Linux 发行版&#…

详细图文手把手教你阿里云注册域名如何托管到CloudFlare DNS服务

1.第一步&#xff1a;注册并登录Cloudflare账号&#xff0c;点击右上角“添加站点”&#xff0c;进入下图页面填写域名&#xff0c;点击继续。 2.第二步&#xff1a;进入页面滑动到最下方&#xff0c;选择Free免费套餐&#xff0c;再次点击继续。 3.第三步&#xff1a;这个页面…

c# 二维图形绘制实践

1.等边三角形 1.1 概述 1.2 代码 using System; using System.Drawing; using System.Windows.Forms;public partial class TriangleForm : Form {public TriangleForm(){//InitializeComponent();// 确保窗体大小足够大&#xff0c;以容纳三角形 this.ClientSize new Siz…

AbMole带你探索细胞的“铁”门:Piezo1通道在椎间盘退变中的关键角色

在生物医学领域&#xff0c;铁是细胞功能不可或缺的元素&#xff0c;但铁的异常积累却可能成为细胞的“隐形杀手”。最近&#xff0c;一项发表在《Bone Research》上的研究&#xff0c;为我们揭开了铁代谢与椎间盘退变之间神秘联系的一角。这项研究不仅深化了我们对铁离子通道P…

5个超实用1688选品技巧!轻松出单999+

1、研究市场需求 通过市场调查和分析&#xff0c;了解目标市场的消费者喜好和趋势。选择具有市场需求且竞争相对较小的产品类别。 用店雷达热销商 品榜和飙升商 品榜。比如做女装类目&#xff0c;选择“女士T恤”我们可以根据日、周、月为时间维度下商品的销售笔数、件数、销…