总结文件对象方法:
文件对象方法 | |
---|---|
f.read() | 有参数表从开头读多少个字节,没有读取所有内容。读小文件推荐 |
f.readline() | 读取一行内容,光标移动到第二行首部.读大文件推荐,或者 for line in 遍历 |
f.readlines() | 读取每一行内容,存放于列表中.返回值是一个列表包含'\n'.读小文推荐 |
f.write() | f.write('1111\n222\n') #针对文本模式的写,需要自己写换行符。内容必须是 字符串 |
f.write() | f.write('1111\n222\n'.encode('utf-8')) #针对b模式的写,需要自己写换行符。返回是int 字符数 |
f.writelines() | f.writelines(['333\n','444\n']) #文本模式。列表元素必须是 字符串 |
f.writelines() | f.writelines([bytes('333\n',encoding='utf-8'),'444\n'.encode('utf-8')]) #b模式 |
f.seek(x,y) | seek(x, 0):从开始位置向右 x 个字符 |
f.seek(x,y) | seek(x, 1):当前位置往右移动 x 个字符 |
f.seek(x,y) | seek(-x, 2):文件的结尾向左移动 x 个字符 |
f.tell() | 返回文件的当前位置 |
f.truncate() | 清空文件,配合f.seek(0) 使用,调整指针位置。 |
f.closed | 文件是否关闭 |
f.flush() | 立刻将文件内容从内存刷到硬盘 |
f.readable() | 文件是否可读 |
f.writable() | 文件是否可写 |
f.name | 文件名字 |
文件操作
一、文件
应用程序向操作系统发出指令,实际是操作硬盘。可以将数据永久保存到硬盘中去
二、如何使用文件:
1.打开文件 2.读写文件 3.关闭文件。
文件操作的基本步骤:1.打开文件 2.读写文件 3.关闭文件。
四、chardet识别文件编码
- chardet.detect(data) # data为 文件内容,返回一个字典。
- 字典为:{'encoding': 编码, 'confidence': 可信度, 'language': 语言}
五、with上下文管理
打开一个:with open('a.txt','w') as f:
打开多个:with open('a.txt','r') as read_f,open('b.txt','w') as write_f:
六、文件的操作模式
1.控制文件读写操作的模式
r(默认的):只读,指针在开头
w:只写 ,指针在开头
a:只追加写,指针在末尾
r 、w、a一般运用场景:
1. `r 一般读取文件,可以运用于用户是否注册,登录是否成功`
2. `w 一般用于新建新文件,比如 文件拷贝功能,打开老文件,重新写入新文件`
3. `a 一般用于打开老的文件。如果注册功能,记录日志。`
2.控制文件读写内容的模式
大前提: tb模式均不能单独使用,必须与r/w/a之一结合使用
t(默认的):文本模式
1. 读写文件都是以字符串为单位的
2. 只能针对文本文件
3. 必须指定encoding参数
b:二进制模式:
1.读写文件都是以bytes/二进制为单位的,任何文件都可以用b模式读取或写入
2. 可以针对所有文件
3. 一定不能指定encoding参数
七、操作文件的方法:
# 读操作
f.read() # 读取所有内容,执行完该操作后,文件指针会移动到文件末尾
f.readline() # 读取一行内容,光标移动到第二行首部
f.readlines() # 读取每一行内容,存放于列表中
# 写操作
f.write('1111\n222\n') # 针对文本模式的写,需要自己写换行符
f.write('1111\n222\n'.encode('utf-8')) # 针对b模式的写,需要自己写换行符
f.writelines(['333\n','444\n']) # 文件模式
f.writelines([bytes('333\n',encoding='utf-8'),'444\n'.encode('utf-8')]) #b模式
bytes===>二进制
1. 字符串编码encode之后的结果
1.1 "字符串".encode("utf-8")
1.2 bytes("字符串",encoding="utf-8")
1. b"必须是纯英文字符"
2. b模式下打开文件,读取的内容
用处:可以存到硬盘里面去
循环读取文件的两种方式:
1. for line in f:
pass
2. while True:
data = f.read(1024)
#data=f.readline()
if len(data) == 0:
break
八、主动控制文件内指针移动seek():
# 0: 默认的模式,该模式代表指针移动的字节数是以文件开头为参照的
# 1: 该模式代表指针移动的字节数是以当前所在的位置为参照的
# 2: 该模式代表指针移动的字节数是以文件末尾的位置为参照的
# 强调:其中0模式可以在t或者b模式使用,而1跟2模式只能在b模式下用
九、修改文件的两种方式:
1.将文件内容发一次性全部读入内存,然后在内存中修改完毕后再覆盖写回原文件
2.以读的方式打开原文件,以写的方式打开一个临时文件,一行行读取原文件内容,修改完后写入临时文件..., 删掉原文件,将临时文件重命名原文件名
3.r+读出内容修改---清空(truncate)--写入 # 这条制作参考。同时又读又写,工作中很少这么去干
先看个案例:
filename = 'data.log'
# 打开文件(a+ 追加读写模式)
# 用 with 关键字的方式打开文件,会自动关闭文件资源
with open(filename, 'w+', encoding='utf-8') as file:
print('文件名称: {}'.format(file.name)) # 文件名称: data.log
print('文件编码: {}'.format(file.encoding)) # 文件编码: utf-8
print('文件打开模式: {}'.format(file.mode)) # 文件打开模式: w+
print('文件是否可读: {}'.format(file.readable())) # True
print('文件是否可写: {}'.format(file.writable())) # True
print('此时文件指针位置为: {}'.format(file.tell())) # 0 r r+ w w+ 打开文件指针都是在开头
# 写入内容
# f.write()返回是int字符数
num = file.write("第一行内容\n")
print('写入文件 {} 个字符'.format(num)) # 写入文件 6 个字符
# 文件指针在文件尾部,故无内容
print(file.readline(), file.tell()) # 17
# 改变文件指针到文件头部
file.seek(0)
# 改变文件指针后,读取到第一行内容
print(file.readline(), file.tell()) # 第一行内容 17
# seek(0)修改文件的指针后,却不会影响到写入的位置
file.write('第二次写入的内容\n')
# 文件指针又回到了文件尾
print(file.readline(), file.tell()) # 43
# file.read() 从当前文件指针位置读取指定长度的字符
file.seek(0)
# 读取指定字符数 f.read(int)
print(file.read(9))
# 按行分割文件,返回字符串列表
file.seek(0)
# readlines() 返回的是一个列表,包括\n
print(file.readlines())
# 迭代文件对象,一行一个元素 # ['第一行内容\n', '第二次写入的内容\n']
file.seek(0)
# 文件对象可以for循环遍历,遍历的是每行的数据
for line in file:
print(line, end='')
# 关闭文件资源
if not file.closed: # with上下文处理器,自动关闭
file.close()
结果:
文件名称: data.log
文件编码: utf-8
文件打开模式: w+
文件是否可读: True
文件是否可写: True
此时文件指针位置为: 0
写入文件 6 个字符
17
第一行内容
17
43
第一行内容
第二次
['第一行内容\n', '第二次写入的内容\n']
第一行内容
第二次写入的内容
一、什么是文件
文件就是操作系统提供给应用程序来操作硬盘虚拟概念,用户或应用程序通过操作文件,可以将自己的数据永久保存下来
为什么要用文件:
用户/应用程序可以通过文件将数据永久保存到硬盘中去。
用户/应用程序直接操作的是文件,对文件进行的所有操作,都是在向操作系统发送系统调用,然后再操作将其转换成具体的硬盘操作
二、如何用文件:open()
-
控制文件读写内容的模式:t和b
- 强调:t和b不能单独使用,必须跟r/w/a连用
- t文本 (默认的模式)
- 1.读写都以str (unicode)为单位的
- 2.文本文件
- 3.必须指定encoding = 'utf-8'
- b 二进制/bytes
控制文件读写操作的模式
文件打开模式:
三、文件操作的基本步骤:
打开文件
字符串文件路径前面加个r
读写文件
-
关闭文件
# -*- coding: utf-8 -*- """ =========================== # @Time : 2020/7/31 9:56 # @File : 基本操作流程.py # @Author: adeng # @Date : 2020/7/31 ============================ """ # 基本流程 # 1. 打开文件,得到文件句柄并赋值给一个变量 # 2.读写文件 # 3.关闭文件---f.close() # 1. t文本的流程 # 打开文件 # r 只读模式【默认模式,文件必须存在,不存在则抛出异常】 # 文件打开的原则是“ 以什么编码格式保存的,就以什么编码格式打开 ” f = open(r'adeng.txt',mode="r", encoding="utf-8") # 默认模式是r # f = open('adengXXX.txt',mode="r", encoding="utf-8") # 默认模式是r # 这里注释的代码,文件不存在会报错 # 读文件 # f.read() 读取所有内容,光标移动到文件末尾,小文件考虑,大文件消耗cpu过大 data = f.read() print(data) # 关闭文件 f.close() """ 输出: 我是阿登 hello word!! """ print("二进制读文件".center(50,'-')) # 二进制读文件 #‘rb’表示以二进制读模式(硬盘存为存的二进制打开就为二进制,并且不再需要指定编码) f = open(r'adeng.txt',mode="rb") # encoding="utf-8" rb不指定编码 print("文件模式:", f.mode) # 读文件 # f.read() 读取所有内容,光标移动到文件末尾,小文件考虑,大文件消耗cpu过大 data = f.read() # data = f.read().decode("utf-8") # 跟代码24行读取的一致.用了decode print(data) # 关闭文件 f.close() """ 输出: b'\xef\xbb\xbf\xe6\x88\x91\xe6\x98\xaf\xe9\x98\xbf\xe7\x99\xbb\r\nhello word!!' """
1、f.close() #回收操作系统打开的文件资源
2、del f #回收应用程序级的变量
# 顺序先1 才能2
指定文件编码
- rt模式方便了文件的读写,但仅限文本文件。可以参考二进制文件的写需要编码
- encoding参数没有,会以默认的编码读写,在不同的系统容易报错
# -*- coding: utf-8 -*-
"""
===========================
# @Time : 2020/8/10 10:58
# @File : 03文件指定编码.py
# @Author: adeng
# @Date : 2020/8/10
============================
"""
"""
encoding参数不指定编码,带来的影响
linux默认编码:utf-8
苹果系统默认编码:utf-8
win默认编码:utf-8
"""
# 相对路径现在有一个文件 中文01.txt 编码是utf-8
f = open("中文01.txt",mode="rt")
res = f.read() # UnicodeDecodeError: 'gbk' codec can't decode byte 0xaf in position 8: illegal multibyte sequence
"""
上面19,20行两行代码干了什么事?
19行:pyhon解释器(应用程序)赋值给f一个变量,生成了一个文件类型的内存空间。open()函数指应用程序向操作系统windowns发出指定以文本读取的方式
打开文件中文01.txt
20行:操作系统读取硬盘的内容到内存中去,并用gbk去decode解码。
上面20行的代码会报错,因为windowns默认是GBK编码。rt模式必须是unicode,就是str类型。encoding参数没有指定utf-8,而是默认以GBK解码,所以报错。
如果你用的苹果系统就不会报错。为了防止不同系统读取文件发生错误,我们得给encoding指定什么格式去解码。正确的写法如下:
"""
f = open("中文01.txt", mode="rt", encoding="utf-8")
res = f.read()
print(res) # 我是阿登
# 有了 encoding ="编码" 调用write方法会默认以encoding的编码写入到硬盘。如果没有需要转换编码再写入。所以rt模式方便了文件的读写,但仅限文本文件。可以参考二进制文件的写需要编码。
四、chardet识别文件编码
- chardet.detect(data) # data为 文件内容,返回一个字典。
- 字典为:{'encoding': 编码, 'confidence': 可信度, 'language': 语言}
# -*- coding: utf-8 -*-
"""
===========================
# @Time : 2020/8/1 15:59
# @File : file_detection.py
# @Author: adeng
# @Date : 2020/8/1
============================
"""
import chardet
'''
pip3 install chardet 第三方包没有就安装
'''
# 在file_detection.py这个目录中创建一个编码01.txt是文档。我们现在不知道他的编码格式。等会读取就用rb模式
def file_encoding(filepath):
"""
filepath: 文件的路径,非目录
"""
with open(filepath,"rb") as f1 :
data = f1.read()
result = chardet.detect(data) # {'encoding': 编码, 'confidence': 可信度, 'language': 语言}
print(result)
encoding = result.get("encoding")
return encoding
# 之后我们要打开一个文件 就可以直接调用file_mode(filepat) 这个函数返回结果作为open()函数encoding参数值
file_path = r"I:\python20\softwaredate\py_basics\文件操作\文件编码检测\编码01.txt"
with open(file_path,mode="r",encoding=file_encoding(file_path)) as f:
datas = f.read()
print(datas)
"""
结果
\xef\xbb\xbf\xe6\x88\x91\xe6\x98\xaf\xe9\x98\xbf\xe7\x99\xbb\r\nhello word!!
史学界认为,解放军成立的事件,是在1927年的“八一”南昌起义打响了武装反抗国民党反动派的第一枪,
宣告我党独立领导革命武装和创建革命军队的开始。所以从1927年到2020年,是建军93周年。建军节的诞生之地1933年7月11日,
中华苏维埃共和国临时中央政府决定将8月1日作为中国工农红军成立纪念日。
从此,每年8月1日就成为中国工农红军和后来中国人民解放军的建军节。当年8月1日,在瑞金叶坪红军广场举行了历史上第一个“八一”纪念活动,
并且当日傍晚在瑞金城南竹马岗举行了红军阅兵式和分列式。从此,8月1日正式成为人民军队的建军节。因此,可以说南昌是军旗升起的地方,
而瑞金是八一建军节诞生的地方。
"""
# chardet.detect(data) 检查文本内容编码类型
五、with上下文管理
# 1、在执行完子代码块后,with 会自动执行f.close()
with open('a.txt','w') as f:
pass
# 2、可用用with同时打开多个文件,用逗号分隔开即可
with open('a.txt','r') as read_f,open('b.txt','w') as write_f:
data = read_f.read()
write_f.write(data)
案例:一个文件名是a.txt,现在需要复制a.txt到一个新文件b.txt,用with上下文管理如何操作
import os
# 案例:一个文件名是a.txt,现在需要复制a.txt到一个新文件b.txt,用with上下文管理如何操作
"""
分析要复制一个文件,需要得到这个文件的内容
然后写入到另外一个文件
"""
with open("a.txt",mode="r+",encoding="utf-8") as f1,\
open("b.txt",mode="w",encoding="utf-8") as f2:
f2.write(f1.read())
# os.remove("a.txt")
# os.rename("b.txt", "a.txt")
"""
如果复制文件到另外一个文件,原文件删除,新文件重命名为原文件。 请看注释掉的代码
"""
# 强调:
# 1、硬盘空间是无法修改的,硬盘中数据的更新都是用新内容覆盖旧内容
# 2、内存中的数据是可以修改的
# 另外一种方式:第一个文件一行行的读,第2个文件一行行的写。这样大文件内存消耗会小得多
with open("a.txt",mode="r+",encoding="utf-8") as f1,\
open("b.txt",mode="w",encoding="utf-8") as f2:
for line in f1:
f2.write(line)
# os.remove("a.txt")
# os.rename("b.txt", "a.txt")
结果:
六、文件的操作模式
1.控制文件读写操作的模式
r(默认的):只读,指针在开头
w:只写 ,指针在开头
-
a:只追加写,指针在末尾
r 、w、a一般运用场景:
r 一般读取文件,可以运用于用户是否注册,登录是否成功
w 一般用于新建新文件,比如 文件拷贝功能,打开老文件,重新写入新文件
a 一般用于打开老的文件。如果注册功能,记录日志。
案例一:r 模式的使用
# r只读模式: 在文件不存在时则报错,文件存在文件内指针直接跳到文件开头
with open('adeng01.txt',mode='r',encoding='utf-8') as f:
res=f.read() # 会将文件的内容由硬盘全部读入内存,赋值给res
print("第一次读取".center(40,"="))
print(res)
print("第2次读取".center(40, "="))
# f.seek(0,0)
print(f.tell())
res1 = f.read() # 会发现第2次读取是空,是因为read()读取所有内容,指针放在末尾. f.seek(0)调整光标位置,又能打印出来了。
print(res1)
#db.txt文件的内容:
adeng:123456
向佳:123456
维维:123456
陈勇:123456
徐州:123456
# 实现登录认证的一个小功能,判断用户是否登录成功
inp_name = input("输入你的用户名:").strip()
inp_pwd = input("输入你的密码:").strip()
with open(r"db.txt",mode="rt", encoding="utf-8") as f:
for line in f :
user,pwd = line.strip("\n").split(":") #
if user ==inp_name and pwd == inp_pwd:
print("登录成功")
break # 登录成功 跳出循环
else: # 循环结束加else,判定是否真的没登录成功
print("账号或者用户名输入错误")
案例二:w 模式的使用
# w只写模式: 在文件不存在时会创建空文档,文件存在会清空文件,文件指针跑到文件开头
# 一个中文相当于=3个字符,1个英文=1个,\n=2个
with open('b.txt',mode='w+',encoding='utf-8') as f:
f.write('你好\n')
print(f.tell())
f.seek(0,0)
f.readline()
print(f.tell())
f.write('我好\n')
print(f.tell())
f.write('大家好\n')
print(f.tell())
f.write('111\n222\n333\n')
结果:
9
9
17
28
#强调:
# 1 在文件不关闭的情况下,连续的写入,后写的内容一定跟在前写内容的后面.
# 2 如果重新以w模式打开文件,则会清空文件内容
# W 模式一般用在创作全新的文件,因为如果w模式打开原文件,会先清空再写入。
# 案例 拷贝功能 原来的文件读出来,写入到新文件。
with open("b.txt","r",encoding="utf-8") as f1,open("c.txt","w",encoding="utf-8") as f2:
for line in f1:
f2.write(line)
案例三:a 模式的使用
# a只追加写模式: 在文件不存在时会创建空文档,文件存在会将文件指针直接移动到文件末尾
with open('c.txt',mode='a',encoding='utf-8') as f:
f.write('44444\n')
f.write('55555\n')
#强调 w 模式与 a 模式的异同:
# 1 相同点:在打开的文件不关闭的情况下,连续的写入,新写的内容总会跟在前写的内容之后
# 2 不同点:以 a 模式重新打开文件,不会清空原文件内容,会将文件指针直接移动到文件末尾,新写的内容永远写在最后
# a 模式用来在原来的文件内存的基础上写入新的内容,比如记录日志,注册功能。
# 小练习:实现注册功能:
# 为什么不能用w模式写呢,w都清空原来文件了,你原来用户都消失了,能这么干吗?
name=input('username>>>: ').strip()
pwd=input('password>>>: ').strip()
with open('db1.txt',mode='a',encoding='utf-8') as f:
info='%s:%s\n' %(name,pwd)
# info = f"{name}:{pwd}"
f.write(info)
py# 用户注册,判定用户是否注册,提示用户已注册还是未注册,密码长度6--12.
name=input('username>>>: ').strip()
pwd=input('password>>>: ').strip()
with open("db.txt",mode="rt",encoding="utf-8") as f1:
for line in f1:
user, pwd1= line.strip().split(":")
if name == user:
print('用户已注册')
break
else:
print(f"{name}可以注册")
if 6<=len(pwd)<=12:
with open("db.txt", mode="at", encoding="utf-8") as f2:
f2.write(f"{name}:{pwd}\n")
else:
if len(pwd) <6:
print("密码长度小于6位")
else:
print("密码长度大于12位")
案例四:+ 模式的使用(了解)
# r+ w+ a+ :可读可写
#在平时工作中,我们只单纯使用r/w/a,要么只读,要么只写,一般不用可读可写的模式
adeng01.txt文件内容:adeng:123456
with open(r"adeng01.txt",mode="r+", encoding="utf-8") as f:
f.write("ren") # r+写入不会清空,但是会覆
# 写入后覆盖了ade 变成了 renng:123456
2.控制文件读写内容的模式
重点对待:
大前提: tb模式均不能单独使用,必须与r/w/a之一结合使用
t(默认的):文本模式
1. 读写文件都是以字符串为单位的
2. 只能针对文本文件
3. 必须指定encoding参数
b:二进制模式:
1.读写文件都是以bytes/二进制为单位的,任何文件都可以用b模式读取或写入
2. 可以针对所有文件
3. 一定不能指定encoding参数
案例一:t 模式的使用
# t 模式:如果我们指定的文件打开模式为r/w/a,其实默认就是rt/wt/at
with open('a.txt',mode='rt',encoding='utf-8') as f:
res=f.read()
print(type(res)) # 输出结果为:
with open('a.txt',mode='wt',encoding='utf-8') as f:
s='abc'
f.write(s) # 写入的也必须是字符串类型
#强调:t 模式只能用于操作文本文件,无论读写,都应该以字符串为单位,而存取硬盘本质都是二进制的形式,
当指定 t 模式时,内部帮我们做了编码与解码
案例二: b 模式的使用
# b: 读写都是以二进制位单位
with open(r'美女.png',mode='rb') as f:
data=f.read()
print(data,type(data)) # 输出结果为:
with open(r'aa.txt',mode='wb') as f:
msg="你好"
res=msg.encode('utf-8') # res为bytes类型,wb模式字符串写入到硬盘需要encode编码
f.write(res) # 在b模式下写入文件的只能是bytes类型
#强调:b模式对比t模式
1、在操作纯文本文件方面t模式帮我们省去了编码与解码的环节,b模式则需要手动编码与解码,所以此时t模式更为方便
2、针对非文本文件(如图片、视频、音频等)只能使用b模式
# 小练习: 编写拷贝工具
src_file=input('源文件路径: ').strip()
dst_file=input('目标文件路径: ').strip()
with open(r'%s' %src_file,mode='rb') as read_f,open(r'%s' %dst_file,mode='wb') as write_f:
for line in read_f: # 循环读取文件
# print(line)
write_f.write(line)
七、操作文件的方法
重点对待
# 读操作
f.read() # 读取所有内容,执行完该操作后,文件指针会移动到文件末尾
f.readline() # 读取一行内容,光标移动到第二行首部
f.readlines() # 读取每一行内容,存放于列表中
# 强调:
# f.read()与f.readlines()都是将内容一次性读入内容,如果内容过大会导致内存溢出,若还想将内容全读入内存,则必须分多次读入,有两种实现方式:
# 方式一
with open('a.txt',mode='rt',encoding='utf-8') as f:
for line in f:
print(line) # 同一时刻只读入一行内容到内存中
# 方式二
with open('1.mp4',mode='rb') as f:
while True:
data=f.read(1024) # 同一时刻只读入1024个Bytes到内存中
if len(data) == 0:
break
print(data)
# 写操作
f.write('1111\n222\n') # 针对文本模式的写,需要自己写换行符
f.write('1111\n222\n'.encode('utf-8')) # 针对b模式的写,需要自己写换行符
f.writelines(['333\n','444\n']) # 文件模式
f.writelines([bytes('333\n',encoding='utf-8'),'444\n'.encode('utf-8')]) #b模式
bytes===>二进制
- 字符串编码encode之后的结果
- "字符串".encode("utf-8")
- bytes("字符串",encoding="utf-8")
- b"必须是纯英文字符"
- b模式下打开文件,读取的内容
用处:可以存到硬盘里面去
循环读取文件的两种方式:
# 方式一:
with open('a.txt',mode='rt',encoding='utf-8') as f:
for line in f:
print(line) # 同一时刻只读入一行内容到内存中
# 方式二 一行读取的内容很多时候,大文件采取的策略
with open('1.mp4',mode='rb') as f:
while True:
data=f.read(1024) # 同一时刻只读入1024个Bytes到内存中
if len(data) == 0:
break
print(data)
# 方式三 读取一行,这个和方式一差不多。选择一吧 这个知道就行。for循环比while循环速度快
with open('1.mp4',mode='rb') as f:
while True:
data=f.readline()
if len(data) == 0:
break
print(data)
了解
f.readable() # 文件是否可读
f.writable() # 文件是否可写
f.closed # 文件是否关闭
f.encoding # 如果文件打开模式为b,则没有该属性
f.flush() # 立刻将文件内容从内存刷到硬盘
f.name # 文件名字
八、主动控制文件内指针移动seek()
文件内指针的移动都是Bytes/字节为单位的,唯一例外的是t模式下的read(n),n以字符为单位
#大前提:文件内指针的移动都是Bytes/字节为单位的,唯一例外的是t模式下的read(n),n以字符为单位
with open('a.txt',mode='rt',encoding='utf-8') as f:
data=f.read(3) # 读取3个字符
with open('a.txt',mode='rb') as f:
data=f.read(3) # 读取3个Bytes
with open('c.txt',mode='rt') as f:
# f.seek(1,1) # t 模式不能在 1模式 使用
f.seek(1,2) # t 模式不能在 2模式 使用
# 文件xx.txt有 12字节
f.seek(1,0)
f.seek(2,0)
f.seek(3,0)
# 最终的位置是 3
f.seek(1,1)
f.seek(2,1)
f.seek(3,1)
# 最终的位置是1+2+3 =6
f.seek(-1,2)
f.seek(-2,2)
f.seek(-3,2)
# 最终的位置是文件末尾向左移动3个字节的位置,文件有12个字节这里就是 9
# 之前文件内指针的移动都是由读/写操作而被动触发的,若想读取文件某一特定位置的数据,则则需要用f.seek方法主动控制文件内指针的移动,详细用法如下:
# f.seek(指针移动的字节数,模式控制):
# 模式控制:
# 0: 默认的模式,该模式代表指针移动的字节数是以文件开头为参照的
# 1: 该模式代表指针移动的字节数是以当前所在的位置为参照的
# 2: 该模式代表指针移动的字节数是以文件末尾的位置为参照的
# 强调:其中0模式可以在t或者b模式使用,而1跟2模式只能在b模式下用
案例一: 0模式详解
# a.txt用utf-8编码,内容如下(abc各占1个字节,中文“你好”各占3个字节)
abc你好
# 0模式的使用
with open('a.txt',mode='rt',encoding='utf-8') as f:
f.seek(3,0) # 参照文件开头移动了3个字节
print(f.tell()) # 查看当前文件指针距离文件开头的位置,输出结果为3
print(f.read()) # 从第3个字节的位置读到文件末尾,输出结果为:你好
# 注意:由于在t模式下,会将读取的内容自动解码,所以必须保证读取的内容是一个完整中文数据,否则解码失败
with open('a.txt',mode='rb') as f:
f.seek(6,0)
print(f.read().decode('utf-8')) #输出结果为: 好
案例二: 1模式详解
# 1模式的使用
with open('a.txt',mode='rb') as f:
f.seek(3,1) # 从当前位置往后移动3个字节,而此时的当前位置就是文件开头
print(f.tell()) # 输出结果为:3
f.seek(4,1) # 从当前位置往后移动4个字节,而此时的当前位置为3
print(f.tell()) # 输出结果为:7
案例三: 2模式详解
# a.txt用utf-8编码,内容如下(abc各占1个字节,中文“你好”各占3个字节)
abc你好
# 2模式的使用
with open('a.txt',mode='rb') as f:
f.seek(0,2) # 参照文件末尾移动0个字节, 即直接跳到文件末尾
print(f.tell()) # 输出结果为:9
f.seek(-3,2) # 参照文件末尾往前移动了3个字节
print(f.read().decode('utf-8')) # 输出结果为:好
# 小练习:实现动态查看最新一条日志的效果
import time
with open('access.log',mode='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='')
文件追加写入,然后动态查看最新一条日志的效果
#文件追加.py的代码
import random
import time
for i in range(10):
with open("access.log",mode="at", encoding="utf-8") as f:
f.write(f"xxx{random.randint(1,100000)}下班了,阿登今天不加班\n")
time.sleep(1.5)
pass
# 此文件追加写入access.log,tail -f.py负责动态实时查看
------------------------------------------------------------------------------------
#tail -f.py的代码
import time
# 模仿 tail -f XXX.log 实现动态查看最新一条日志的效果
with open("access.log",mode="rb") as f:
f.seek(0,2) # 检测文件末尾.2模式只能b模式用
while True:
line = f.readline()
if not line:
# 没有日志写入
time.sleep(1)
else:
print(line.decode("utf-8"),end=" ")
九、修改文件的两种方式:
# 文件d.txt内容如下
张一蛋 山东 179 49 12344234523
李二蛋 河北 163 57 13913453521
王全蛋 山西 153 62 18651433422
# 执行操作
with open('d.txt',mode='r+t',encoding='utf-8') as f:
f.seek(9)
f.write('<妇女主任>')
# 文件修改后的内容如下
张一蛋<妇女主任> 179 49 12344234523
李二蛋 河北 163 57 13913453521
王全蛋 山西 153 62 18651433422
# 强调:
# 1、硬盘空间是无法修改的,硬盘中数据的更新都是用新内容覆盖旧内容
# 2、内存中的数据是可以修改的.
文件修改方式一
# 实现思路:将文件内容发一次性全部读入内存,然后在内存中修改完毕后再覆盖写回原文件
# 优点: 在文件修改过程中同一份数据只有一份
# 缺点: 会过多地占用内存
"""
e.txt的内容如下:
阿登一个单身就是想找个小姐姐谈恋爱。
找个小姐一定得爱着阿登哥哥!!!
如果加个爱阿登的期限:
□□□□□□□□□一万年!!!□□□□□□□
"""
with open('e.txt',mode='rt',encoding='utf-8') as f:
data=f.read()
with open('e.txt',mode='wt',encoding='utf-8') as f:
f.write(data.replace('阿登','向佳'))
文件修改方式二
# 实现思路:以读的方式打开原文件,以写的方式打开一个临时文件,一行行读取原文件内容,修改完后写入临时文件...,删掉原文件,将临时文件重命名原文件名
# 优点: 不会占用过多的内存
# 缺点: 在文件修改过程中同一份数据存了两份
import os
with open('e.txt',mode='rt',encoding='utf-8') as f1,\
open("e01.txt", mode="wt", encoding="utf-8") as f2:
for line in f1:
f2.write(line.replace("阿登","向佳"))
os.remove("e.txt")
os.rename("e01.txt", "e.txt")
文件修改方式三:参考
# 方式一修改文件:读出内容修改---清空--写入
with open(r"e.txt",mode="rb+") as f1:
data = f1.read()
# 对读出来的内容进行解码
data = data.decode("utf-8").replace("阿登","向佳")
print(data)
# 指针指定到开头
f1.seek(0,0)
# 清空 truncate
f1.truncate()
f1.write(data.encode("utf-8"))
总结文件对象方法:
文件对象方法 | |
---|---|
f.read() | 有参数表从开头读多少个字节,没有读取所有内容。读小文件推荐 |
f.readline() | 读取一行内容,光标移动到第二行首部.读大文件推荐,或者 for line in 遍历 |
f.readlines() | 读取每一行内容,存放于列表中.返回值是一个列表包含'\n'.读小文推荐 |
f.write() | f.write('1111\n222\n') #针对文本模式的写,需要自己写换行符。内容必须是 字符串 |
f.write() | f.write('1111\n222\n'.encode('utf-8')) #针对b模式的写,需要自己写换行符。返回是int 字符数 |
f.writelines() | f.writelines(['333\n','444\n']) #文本模式。列表元素必须是 字符串 |
f.writelines() | f.writelines([bytes('333\n',encoding='utf-8'),'444\n'.encode('utf-8')]) #b模式 |
f.seek(x,y) | seek(x, 0):从开始位置向右 x 个字符 |
f.seek(x,y) | seek(x, 1):当前位置往右移动 x 个字符 |
f.seek(x,y) | seek(-x, 2):文件的结尾向左移动 x 个字符 |
f.tell() | 返回文件的当前位置 |
f.truncate() | 清空文件,配合f.seek(0) 使用,调整指针位置。 |
f.closed | 文件是否关闭 |
f.flush() | 立刻将文件内容从内存刷到硬盘 |
f.readable() | 文件是否可读 |
f.writable() | 文件是否可写 |
f.name | 文件名字 |