文件的高级操作
三大模式
如果我们想要既读取又写入可以在r/w/a这三种模式后面加一个‘+’号,这样就能实现既读取又写入。
我们先讲一讲r+吧,我们在test.txt文件中先写入‘你好,世界’
with open('test.txt', 'r+', encoding='utf8') as fr: ##当test.txt文件不存在时会报错
data = fr.read()
print(fr.writable()) # True ##这个可以证明在r+模式下是可以进行写入操作的
fr.write('x = 10') ## 发现test.txt文件中的内容是:你好,世界x = 10 ,发现r+模式下写入操作是属于追加的操作的。
既然已经了解了r+,那让我们看看w+
with open('test.txt', 'w+', encoding='utf8') as fw:
print(fw.readable()) # True ##这个可以证明在w+模式下是可以进行读取操作的
fw.write('x = 10') # x = 10 ##可以证明这个写入会清除之前的内容
data = fw.read() ##由于写入完成后指针是在最后面所以read()读取不到东西的
print(data) ##直接打印了个空行
还有一个就是a+
##可以想象a+也是可读可写,并且是在内容的最后写入,并不会删除之前的内容
with open('test.txt', 'a+', encoding='utf8') as fa:
data = fa.read() # 指针在末尾读取不到内容
print(data) # 一个空行
fa.write('x = 10') # 你好,世界x = 10
整理:
模式 | 描述 |
---|---|
r | 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。 |
rb | 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。 |
r+ | 打开一个文件用于读写。文件指针将会放在文件的开头。 |
rb+ | 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。 |
w | 打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
wb | 以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
w+ | 打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
wb+ | 以二进制格式打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
a | 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
ab | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
a+ | 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。 |
ab+ | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。 |
由于默认是以t模式打开,所以上面表格不在添加t
三大模式总结:
模式 | r | r+ | w | w+ | a | a+ |
---|---|---|---|---|---|---|
读 | + | + | + | + | ||
写 | + | + | + | + | + | |
创建 | + | + | + | + | ||
覆盖 | + | + | ||||
指针在开始 | + | + | + | + | ||
指针在结尾 | + | + |
文件对象的方法
读取:read()
with open("test.txt", "r", encoding="utf-8") as fr:
str = fr.read()
print(str) ## 以字符串的形式输出文件中的内容
str = fr.read(5)
print(str) ## 输出文件前五个字符
读取一行:readline()
with open("test.txt", "r", encoding="utf-8") as fr:
str = fr.readline()
print(str) ## 以字符串的形式输出文件中第一行的内容
读取所有行:readlines()
with open("test.txt", "r", encoding="utf-8") as fr:
str = fr.readlines()
print(str) # ['你好,世界\n', 'x = 10'] ## 返回一个字符串列表,列表每个元素都是一行的内容
还有一个方式是直接迭代文件对象
with open("test.txt", "r", encoding="utf-8") as fr:
for i in fr:
print(i,end='') #你好,世界
#x = 10
按字节位移:seek()
- seek(x,0) : 从起始位置即文件首行首字符开始移动 x 个字符
- seek(x,1) : 表示从当前位置往后移动x个字符
- seek(-x,2): 表示从文件的结尾往前移动x个字符
with open('test.txt', 'rb+') as f:
f.write(b'0123456789abcdef')
f.seek(5) # 移动到文件的第六个字节
str = f.read(1) # 读取文件1个字节的内容
print(str) # b'5'
f.seek(-3, 2) # 移动到文件的倒数第三字节
str = f.read(1)
print(str) # b'd'
返回指针所处的位置:tell()
with open('test.txt', 'r', encoding='utf8') as fr:
fr.seek(2, 0) # 从文件头左移两个字节
print(fr.tell()) # 2
截取字节:truncate()
with open('test.txt', 'rb+') as f:
f.write(b'0123456789abcdef')
f.truncate(7) # 截取前七个字符 文件中只留:0123456
文件修改的两种方式
方式一:
将硬盘存放的该文件的内容全部加载到内存,在内存中是可以修改的,修改完毕后,再由内存覆盖到硬盘
import os
with open('37r.txt') as fr,open('37r_swap.txt', 'w') as fw:
data = fr.read() # 全部读入内存,如果文件很大,会很卡
data = data.replace('tank', 'tankSB') # 在内存中完成修改
fw.write(data) # 新文件一次性写入原文件内容
# 删除原文件
os.remove('37r.txt')
# 重命名新文件名为原文件名
os.rename('37r_swap.txt', '37r.txt')
方式二:
将硬盘存放的该文件的内容一行一行地读入内存,修改完毕就写入新文件,最后用新文件覆盖源文件。
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')
函数
函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。
函数能提高应用的模块性,和代码的重复利用率。
函数的定义方式
语法
def 函数名(参数列表):
函数体
定义规则
- 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 ()。
- 任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。
- 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
- 函数内容以冒号起始,并且缩进。
- return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None。
示例:
def hello() :
'''程序员的第一个语句'''
print("Hello World!")
hello() # Hello World! ## 调用函数,执行函数内的代码
print(hello.__doc__) # 程序员的第一个语句
函数的分类
空函数
def login(): ## 定义了一个函数但是没有去实现他的功能
pass
无参函数
def pr_Hello(): ## 定义了一个不需要传递参数的函数
print("Hello World!")
有参函数
def sum_number(num1,num2): ## 定义了一个需要两个参数的函数,在调用该函数的时候需要传递两个参数
print(num1+num2)
参数
形参: 定义阶段才有形参,形式参数,啥也没用,只是占个位置,具有描述意义
实参: 调用阶段才有实参,实际的参数,具有具体的值
必需参数
关键字参数
默认参数
不定长参数
必须参数
必需参数须以正确的顺序传入函数。调用时的数量必须和声明时的一样。
调用 sum_number() 函数,你必须传入一个参数,不然会出现语法错误
def sum_number(num1,num2): ## 定义了一个需要两个参数的函数,在调用该函数的时候需要传递两个参数
print(num1+num2)
sum_number() # sum_number() missing 2 required positional arguments: 'num1' and 'num2'
关键字参数
关键字参数和函数调用关系紧密,函数调用使用关键字参数来确定传入的参数值。
使用关键字参数允许函数调用时参数的顺序与声明时不一致。但是必须参数必须在关键字参数之前
def printme(name, age):
'''打印姓名年龄'''
print(f'{name}——{age}')
printme('Gredae', age = 18) # Gredae——18
默认参数
调用函数时,如果没有传递参数,则会使用默认参数。
def printme(name, age = 18):
'''打印姓名年龄'''
print(f'{name}——{age}')
printme('Gredae') # Gredae——18
printme('nick',32) # nick——32
不定长参数
你可能需要一个函数能处理比当初声明时更多的参数。
加了星号 ***** 的参数会以元组(tuple)的形式导入,存放所有未命名的变量参数。
def printinfo( arg1, *vartuple ):
"打印任何传入的参数"
print ("输出: ",arg1,vartuple)
# 调用printinfo 函数
printinfo( 70, 60, 50 ) # 输出: 70 (60,50)
printinfo( 10 ) # 输出: 10 ##如果在函数调用时没有指定参数,它就是一个空元组
还有一种就是参数带两个星号 *,加了两个星号 * 的参数会以字典的形式导入。
def printinfo( arg1, **vardict ):
"打印任何传入的参数"
print ("输出: ",arg1,vartuple)
# 调用printinfo 函数
printinfo(1, a=2,b=3) # 输出: 1 {'a': 2, 'b': 3}
return 语句
def sum_number( num1, num2 ):
total = num1 + num2
print ("函数内输出 : ", total) # 函数内输出 : 30
return total ## 用于函数的返回并终止函数,可以返回任意数据类型,当返回多个值时默认以元组的形式返回
# 调用sum_number函数
total = sum_number( 10, 20 )
print ("函数外输出 : ", total) # # 函数外输出 : 30