文件的高级应用
文件高级应用可以做到即可读又可写(尽量不要使用)
r+
r+的写入是在原本文件后面追加
# test.py 文件内容为 '''111'''
with open('test.py', 'r+', encoding='utf8') as fr:
data = fr.read()
print(fr.writable())
fr.write('x = 10')
print(data)
结果为:
True
'''111'''
文件内容变为'''111'''x = 10
注意此时打印的data没有x = 10 是因为在写之前就已经读取了
w+
清空文件的功能是W提供的,w+更不要使用
也就是说,f.write()并不是清空文件的罪魁祸首
with open('test.py', 'w+', encoding='utf8') as fr:
print(fr.readable())
fr.write('x = 10')
文件结果变为x = 10
with open('test.py', 'w+', encoding='utf8') as fr:
# print(fr.readable())
# fr.write('x = 10')
data = fr.read()
print(data)
此时文件结果反而什么也没有,并不是不能用read,而是此时文件里已经什么也没有了。如果要问为什么,就是被w清空了
a+
a+则是在原本追加的情况下还能进行读取
with open('test.py', 'a+', encoding='utf8') as fr:
data = fr.read()
print(data)
fr.write('x = 10')
fr.flush()
这个时候你就会发现,依旧是什么都没有打印,但是寻思a也没有清除文本内容呀?而且多次打印后发现,txt文件中的x越来越多,但是却什么都打印不出来。这里就涉及到了一个指针的问题,我会在接下来一一进行阐述
指针
指针是文件的内置方法,其实也就是当你鼠标点击某一行字的时候,那一闪一闪的竖就是指针。那么问题回到上面,为什么明明文本中有数据,但是read()却读不出来呢?这就是因为read函数是从指针的地方开始读,而a+默认指针是在文件的末尾,所以自然什么也读不出来了。之前说的只读模式里一次运行只能读取一次也是相同的道理。
seek
用于改变指针位置后读取
with open('test.py', 'rb') as fr:
fr.seek(1) # 1表示位移1位,默认从文件头开始
fr.seek(1, 0) # 1表示偏移1位,0表示从头开始(这里和第一个一样)
fr.seek(2, 1) # 1表示偏移1位,1表示从当前位置开始
fr.seek(0, 2) # 0表示偏移0位,2表示文件末开始,把指针移到文件末
print(fr.read())
结果依次为:
b' = 10x = 10x = 10x = 10x = 10x = 10x = 10x = 10x = 10x = 10'
b' = 10x = 10x = 10x = 10x = 10x = 10x = 10x = 10x = 10x = 10'
b' 10x = 10x = 10x = 10x = 10x = 10x = 10x = 10x = 10x = 10'
b''
因此在配合seek之后,a+也可以读取文件了
with open('test.py', 'a+', encoding='utf8') as fr:
fr.seek(1, 0)
data = fr.read()
print(data)
fr.write('x = 10')
fr.flush()
tell
同于告诉你指针的位置
with open('test.py', 'r', encoding='utf8') as fr:
fr.seek(2, 0)
print(fr.tell()) # 2
read(n)
可以读取文件中的字节
with open('test.py', 'r', encoding='utf8') as fr:
print(fr.read(5)) # x = 1
print(fr.read(6)) # x = 10
truncate截断
只读模式无法使用。只写模式会清空文件,所以一般用于追加模式
with open('test.py', 'a', encoding='utf8') as fr:
fr.truncate(2) # 将 x 后的内容全部清空
文件修改的俩种方式
首先,文件其实并没有修改这一说法,只有覆盖这一说法
因为在你文件里的这段文字的前后,其实可能都满满的存放着别的东西。如果你在这段文字中加上一些东西,也就意味着后面的所有内存都要移动几格,这是不科学的。
而平时修改文件的时候,都是模拟出来的效果,具体的说有两种实现方式。
方式一
import os
with open('test.txt') as fr, \
open('test_swap.txt', 'w') as fw:
data = fr.read() # 全部读入内存,如果文件很大,会很卡
data = data.replace('tank', 'tankSB') # 在内存中完成修改
fw.write(data) # 新文件一次性写入原文件内容
# 删除原文件
os.remove('test.txt')
# 重命名新文件名为原文件名
os.rename('test_swap.txt', '37r.txt')
print('done...')
方式二
import os
with open('37r.txt') as fr,\
open('37r_swap.txt', 'w') as fw:
# 循环读取文件内容,逐行修改
for line in fr:
line = line.replace('jason', 'jasonSB')
# 新文件写入原文件修改后内容
fw.write(line)
os.remove('37r.txt')
os.rename('37r_swap.txt', '37r.txt')
print('done...')
总而言之,修改文件内容的思路为:以读的方式打开原文件,以写的方式打开一个新的文件,把原文件的内容进行修改,然后写入新文件,之后利用os模块的方法,把原文件删除,重命名新文件为原文件名,达到以假乱真的目的
函数
定义函数的方式
def 函数名(): # 定义阶段(造车轮阶段)
"""函数注释写在这里""" # 函数相当于工具, 注释相当于工具的说明书
<代码块>
# 使用 # 调用阶段(开车阶段)
函数名()
def func():
"""func函数的注释"""
# todo:未来写一个开车函数
pass
func()
注意:函数在定义阶段的时候不执行函数整体代码,智能检测到语法错误
print(func.__doc__)
可以知道函数中的注释
函数的简单实例
我们不妨尝试用函数来实现登录注册功能
def register():
"""注册函数"""
username = input('请输入你的用户名:')
pwd = input('请输入你的密码:')
with open('user_info.txt', 'a', encoding='utf8') as fa:
fa.write(f'{username}:{pwd}|')
def login():
"""登录函数"""
username = input('请输入你的用户名:')
pwd = input('请输入你的密码:')
with open('user_info.txt', 'r', encoding='utf8') as fr:
data = fr.read()
user_list = data.split('|')
print(user_list)
user_info = f'{username}:{pwd}'
if user_info in user_list:
print('登录成功')
else:
print('傻逼,密码都忘了')
有没有发现,当函数没有参数的时候,里面的代码块和在外面打的没有什么区别。其实,函数更多的是一种思想,而不是一种技术
函数的三种定义方式
三种方式分别为无参函数,有参函数,空函数
无参函数
def add():
"""无参函数"""
x = input('num1:')
y = input('num2:')
print(int(x) + int(y))
无参函数可以进行单独使用,上面的登录注册也是同理
有参函数
有参函数在函数中增加了参数,再往函数中输入参数之后才能使用
def add(x, y):
"""有参函数"""
print(int(x) + int(y))
print(1)
x = input('num1:')
y = input('num2:')
add(x, y)
结果为:
num1:1
num2:2
3
空函数
顾名思义,里面什么都没有
当你不知道函数怎么写的时候,可以先放一边,等以后再来写
def func(): # 只知道工具叫什么名字,但不知道如何造出这个工具
pass
函数的调用
def add(x, y):
return x+y
res = add(10, 20) # 函数的调用
print(res*12) # 360
这就是函数简单的调用,无参函数一般都是直接执行func(),有参函数则要在括号中输入符合要求的参数
函数的返回值
函数的返回值就是return,当函数执行到return时,直接返回return后面的数值,有一点类似于break的用法,可以配合if函数的使用来返回多种情况的值
def add(x, y):
return (x, y, x + y) # return可以返回任意数据类型
return x, y, x + y # return可以返回任意数据类型,不加括号返回多个值时,默认用元祖的形式返回
到这里函数的基础部分已经结束了。函数并不难,只要多敲几遍熟悉熟悉,相信马上就能熟能生巧