1. 文件基本操作
1.1 文件的概述
- 文件是数据的抽象和集合,是数据存储的一种形式。一篇文章、一段视频、一个可执行程序,都可以被保存为一个文件,并赋予一个文件名。
- 文件是操作系统提供给用户操作硬盘的一种虚拟的概念。用来承接指令和数据。
- 文件拥有 文本文件 和 二进制文件 两种展现形式。
1.2 文件基本操作
操作文件的套路非常固定,一共包含三个步骤:
- 第一步:打开文件
- 第二步:读、写文件
- 读 将文件内容读入内存
- 写 将内存内容写入文件
- 第三步:关闭文件
# 1、打开文件
f=open('a.txt',mode='rt',encoding='utf-8')
# 2、调用文件对象下的读写方法
res=f.read()
# f.write() #写入文件的内容
# 3、关闭文件
f.close() # 回收操作系统资源
补充:
open()
函数的语法格式:# 常用的语法格式: open(file, mode='r', encoding='utf-8') # 文本文件常用 open(file, mode='rb') # 二进制文件常用 # 完整的语法格式: open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) # 参数说明: file: 必填项,文件路径(相对或者绝对路径)。 mode: 文件打开模式,默认是r(只读) buffering: 设置缓冲 encoding: 一般使用utf-8 errors: 报错级别 newline: 区分换行符 closefd: 传入的file参数类型 opener: 设置自定义开启器,开启器的返回值必须是一个打开的文件描述符。
- 绝对路径和相对路径:
- 绝对路径:从根路径位置到指定文件的全路径;
- 相对路径:从当前文件的位置到指定文件的路径;
1.3 with语法 自动关闭文件
with语法 自动关闭文件,相当于帮你执行了
fp.close()
# 语法格式:
with open(file,mode='r') as 文件对象
# 读写操作
……
# 方法一.读写二进制文件
with open("集合2.png",mode="rb") as fp:
res = fp.read()
with open("集合3.png",mode="wb") as fp:
fp.write(res)
# 方法二.继续简化
with open("集合3.png",mode="rb") as fp1 , open("集合4.png",mode="wb") as fp2 :
res = fp1.read()
fp2.write(res)
# 这种简化方式,可以打开多个文件进行读写操作。
1.4 文本文件和二进制文件
文本文件和二进制文件是文件的两种不同的展现形式。
-
t
表示文本模式,默认的,可以不体现出来。- 读写都是以字符串(unicode)为单位
- 只能针对文本文件
- 必须指定字符编码,即必须指定
encoding参数
-
b
表示二进制模式- 读写都是以bytes为单位
- 可以针对所有文件
- 一定不能指定字符编码,即一定不能指定
encoding参数
-
这两种模式都不能单独进行使用,必须配合r、w、a这些操作模式使用。
# encoding参数
# 针对文本文件,在读写的时候建议指定encoding参数,没有指定encoding参数操作系统会使用自己默认的编码。
# linux系统默认utf-8
# windows系统默认gbk
with open('c.txt',mode='rt',encoding='utf-8') as f:
res=f.read() # t模式会将f.read()读出的结果解码成unicode
print(res,type(res))
2. 文件操作模式
2.1 操作模式介绍
文件操作模式:
-
w
:(只写模式)
文件不存在则创建文件,存在的话则打开清空内容,并且将文件指针放在文件的开头。 -
r
:(只读模式)
文件不存在则报错,存在的话则打开文件,并且将文件指针放在文件的开头。 -
a
:(追加模式)
文件不存在则创建文件,存在的话则打开文件,并且将文件指针放在文件的末尾。 -
x
:(只写模式,较少使用)
文件已存在则报错,不存在的话则创建文件,将文件指针放在文件的开头。
扩展模式 (配合打开模式的辅助模式,自己单独不能使用)
+
:增强模式(可以让文件具有读写功能)t
:文本模式(文本),默认的模式,例如:rt = r
;wt = w
等。b
:bytes bytes模式(二进制字节流)
模式参数
参数 | 参数+ | 参数b | 参数b+ |
---|---|---|---|
w/wt | w+/wt+ | wb | wb+ |
r/rt | r+/rt+ | rb | rb+ |
a/at | a+/at+ | ab | ab+ |
x/xt | x+/xt+ | xb | xb+ |
2.2 文件操作详解
r模式(只读)
r(默认的操作模式):只读模式,当文件不存在时报错,当文件存在时文件指针跳到开始位置。
with open('c.txt',mode='rt',encoding='utf-8') as f:
print('第一次读'.center(50,'*'))
res=f.read() # 把所有内容从硬盘读入内存
print(res) # 读取到文件按里的内容。
print('第二次读'.center(50,'*'))
res1=f.read()
print(res1) # 没有内容
# 第二次读,没有读取到文件里的内容,是因为第一次读的时候,文件的指针已经跳转到了文件的末尾位置,而且文件没有关闭,所以第二次读的时候,就在指针的当前位置往下读取。
# 当重新打开一次时,文件指针会又跳转到开始位置,读取数据。
with open('c.txt',mode='rt',encoding='utf-8') as f:
print('第一次读'.center(50,'*'))
res=f.read() # 把所有内容从硬盘读入内存
print(res) # 读取到文件按里的内容。
with open('c.txt', mode='rt', encoding='utf-8') as f:
print('第二次读'.center(50,'*'))
res1=f.read()
print(res1) # 读取到文件按里的内容。
# 案例:匹配登录账号密码
inp_username=input('your name>>: ').strip()
inp_password=input('your password>>: ').strip()
# 验证
with open('user.txt',mode='rt',encoding='utf-8') as f:
for line in f:
username,password=line.strip().split(':')
if inp_username == username and inp_password == password:
print('login successfull')
break
else:
print('账号或密码错误')
w模式(只写)
w:只写模式,当文件不存在时会创建空文件,当文件存在会清空文件,指针位于开始位置。
- 在以w模式打开文件没有关闭的情况下,连续写入,新的内容总是跟在旧的之后;
- 如果重新以w模式打开文件,则会清空文件内容
with open('d.txt',mode='wt',encoding='utf-8') as f:
# f.read() # 报错,不可读
f.write('测试abc\n')
# 1、在以w模式打开文件没有关闭的情况下,连续写入,新的内容总是跟在旧的之后
with open('d.txt',mode='wt',encoding='utf-8') as f:
f.write('123\n')
f.write('234\n')
f.write('345\n')
# 2、如果重新以w模式打开文件,则会清空文件内容
with open('d.txt',mode='wt',encoding='utf-8') as f:
f.write('123\n')
with open('d.txt',mode='wt',encoding='utf-8') as f:
f.write('234\n')
with open('d.txt',mode='wt',encoding='utf-8') as f:
f.write('345\n')
w模式更加适用于创建新的文件,比如复制操作,生成新的复制文件之类的。
# 案例:w模式用来创建全新的文件 # 文件文件的copy工具 src_file=input('源文件路径>>: ').strip() dst_file=input('源文件路径>>: ').strip() with open(r'{}'.format(src_file),mode='rt',encoding='utf-8') as f1,open(r'{}'.format(dst_file),mode='wt',encoding='utf-8') as f2: res=f1.read() f2.write(res)
a模式(只追加)
a:只追加写,在文件不存在时会创建空文档,在文件存在时文件指针会直接调到末尾
with open('e.txt',mode='at',encoding='utf-8') as f:
# f.read() # 报错,不能读
f.write('123\n')
f.write('234\n')
f.write('345\n')
a模式更加适合对原有文件进行追加操作的文件,比如说日志文件等。
# 案例:a模式用来在原有的文件内存的基础之上写入新的内容,比如记录日志、注册 # 注册功能 name=input('your name>>: ') pwd=input('your name>>: ') with open('db.txt',mode='at',encoding='utf-8') as f: f.write('{}:{}\n'.format(name,pwd))
强调 w 模式与 a 模式的异同:
相同点:在打开的文件不关闭的情况下,连续的写入,新写的内容总会跟在前写的内容之后。
不同点:以 a 模式重新打开文件,不会清空原文件内容,会将文件指针直接移动到文件末尾,新写的内容永远写在最后。
+
模式(增强)
+
增强模式:可读可写+不能单独使用,必须配合r、w、a;同理,其性能特点也是依赖于r/w/a的特点的。
例如:
rt+
的特点取决于rt
,当文件不存在时报错,当文件存在时文件指针跳到开始位置。
with open('g.txt',mode='rt+',encoding='utf-8') as f:
# print(f.read()) # 可读
f.write('zhangsan') # 可写
# rt+ 的写是依赖于rt,文件指针跳到开始的位置,所以,rt+的写是覆盖式的写。
with open('g.txt',mode='w+t',encoding='utf-8') as f:
f.write('111\n')
f.write('222\n')
f.write('333\n')
print('====>',f.read()) # 可读,但读不到数据
# wt+ 每次打开文件都是清空文件,文件指针跳转到文件开头,写入之后,紧接着读的话,读取不到任何数据,因为此时的指针位于文件末尾。
with open('g.txt',mode='a+t',encoding='utf-8') as f:
print(f.read()) # 可读,但读不到数据
f.write('444\n')
f.write('5555\n')
print(f.read()) # 可读,同样读不到数据
# at+ 每次打开文件文件指针都位于文件末尾,直接读的话,读取不到任何数据,因为此时的指针位于文件末尾。写入之后读,也是同样的清况。
x模式(只写)
x:只写,在文件不存在时会创建空文档,在文件存在时报错。一般不会使用,鸡肋。
with open('c.txt',mode='x',encoding='utf-8') as f:
f.read() # 报错
with open('d.txt', mode='x', encoding='utf-8') as f:
f.write('哈哈哈')
b模式(二进制)
读写都是以bytes为单位;
可以针对所有文件;
一定不能指定字符编码,即一定不能指定encoding参数;1、在操作纯文本文件方面
t
模式帮我们省去了编码
与解码
的环节,b模式则需要手动编码与解码,所以此时t
模式更为方便
2、针对非文本文件(如图片、视频、音频等)只能使用b
模式。
# 处理非文本文件
with open(r'test.jpg',mode='rb') as f:
res=f.read() # 硬盘的二进制读入内存—>b模式下,不做任何转换,直接读入内存
print(res) # bytes类型—>当成二进制编码(展现的是16进制编码)
print(type(res)) # <class 'bytes'>
# 处理文本文件
with open(r'测试.txt',mode='rb') as f:
res=f.read() # utf-8的二进制
print(res,type(res))
print(res.decode('utf-8')) # 进行解码,实现用户可读
with open(r'd.txt',mode='rt',encoding='utf-8') as f:
res=f.read() # utf-8的二进制->unicode 这里直接可读是因rt模式也插入实现了解码的操作。
print(res) # 用户可读内容
with open(r'测试.txt',mode='wb') as f:
f.write('你好hello'.encode('gbk')) # 写的时候进行编码
# 总结:
# 1、在操作纯文本文件方面 `t`模式帮我们省去了编码与解码的环节,b模式则需要手动编码与解码,所以此时`t`模式更为方便
# 2、针对非文本文件(如图片、视频、音频等)只能使用`b`模式。
- 案例:文件拷贝工具
src_file=input('源文件路径>>: ').strip()
dst_file=input('源文件路径>>: ').strip()
with open(r'{}'.format(src_file),mode='rb') as f1,open(r'{}'.format(dst_file),mode='wb') as f2:
# res=f1.read() # 这样一次读取,内存占用过大
# f2.write(res)
# 循环读取文件实现:
for line in f1:
f2.write(line)
- 循环读取文件实现:
# 方式一:自己控制每次读取的数据的数据量,单位为字节 with open(r'test.jpg',mode='rb') as f: while True: res=f.read(1024) # 1024 if len(res) == 0: break print(len(res)) # 方式二:以行为单位读,但是当一行内容过长时会导致一次性读入内容的数据量过大 with open(r'g.txt',mode='rt',encoding='utf-8') as f: for line in f: print(len(line),line) with open(r'g.txt',mode='rb') as f: for line in f: print(line) with open(r'test.jpg',mode='rb') as f: for line in f: print(line)
3. 文件操作的常用方法
3.1 读方法
read()
:读取所有内容,执行完该操作后,文件指针会移动到文件末尾。- 也可以读取指定字节数,例如:read(10),读取10字节数据。
readline()
:读取一行内容,光标移动到第二行首部。readlines()
:读取每一行内容,存放于列表中。
# 1、readline:一次读一行
with open(r'g.txt',mode='rt',encoding='utf-8') as f:
# res1=f.readline()
# res2=f.readline()
# print(res2)
while True:
line=f.readline()
if len(line) == 0:
break
print(line)
# 2、readlines:类似于read,一起全都读取
with open(r'g.txt',mode='rt',encoding='utf-8') as f:
res=f.readlines()
print(res)
read()
与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)
3.2 写方法
write()
:将指定的文本写入文件writelines()
:将内容是字符串的可迭代性数据写入文件中- 参数:内容为字符串类型的可迭代数据
# writelines():
with open('h.txt',mode='wt',encoding='utf-8') as f:
# f.write('1111\n222\n3333\n')
# l=['11111\n','2222','3333',4444]
l=['11111\n','2222','3333']
# for line in l:
# f.write(line)
f.writelines(l)
with open('h.txt', mode='wb') as f:
l = [
'1111aaa1\n'.encode('utf-8'),
'222bb2'.encode('utf-8'),
'33eee33'.encode('utf-8')
]
# 补充1:如果是纯英文字符,可以直接加前缀b得到bytes类型
l = [b'1111aaa1\n',b'222bb2',b'33eee33']
# 补充2:'上'.encode('utf-8') 等同于bytes('上',encoding='utf-8')
l = [bytes('上啊',encoding='utf-8'),bytes('冲呀',encoding='utf-8'),bytes('小垃圾们',encoding='utf-8')]
3.3 其他方法(了解)
readable()
:判断文件对象是否可读
writable()
:判断文件对象是否可写
flush()
:手动刷新缓冲区,直接把内容写入到文件
# readable()
with open('a.txt',mode='rb') as f:
res = f.readable()
print(res) # True
# writable()
with open('a.txt',mode='rb') as f:
res = f.readable()
print(res) # False
# flush()
"""
注意:在刷新缓冲区之前,读写的数据是保留在缓冲区中,并没有真正的写到文件中。
刷新缓冲区 flush() 的情况:
1.当文件关闭的时候自动刷新缓冲区
2.当整个程序运行结束的时候自动刷新缓冲区
3.当缓冲区写满了 会自动刷新缓冲区
4.手动刷新缓冲区
"""
with open('h.txt', mode='wt',encoding='utf-8') as f:
f.write('哈')
f.flush()
4. 文件扩展操作
4.1 文件指针的移动
-
指针移动的单位都是以bytes/字节为单位
-
只有一种情况特殊:t模式下的read(n),n代表的是字符个数
with open('aaa.txt',mode='rt',encoding='utf-8') as f:
res=f.read(4)
print(res) # abcd,只读取了4个字符。由此验证t模式下的read(n),n代表的是字符个数
- 指针移动方法
seek()
# f.seek(n,模式):n指的是移动的字节个数
# 模式0:参照物是文件开头位置
f.seek(9,0) # 从文件开头右移9个
f.seek(3,0) # 从文件开头右移3个
# 模式1:参照物是当前指针所在位置
f.seek(9,1) # 当前位置右移9个
f.seek(3,1) # 当前位置右移3个,
# 模式2:参照物是文件末尾位置,应该倒着移动,一般是负数。
f.seek(-9,2)
f.seek(-3,2)
注意:只有0模式可以在t下使用,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='')
- 获取文件指针的当前位置
tell()
# a.txt:测试123456
with open('a.txt',mode='rb') as f:
f.seek(6,0)
print(f.tell()) # 6
f.seek(7,0)
res=f.read()
print(res.decode('utf-8')) # 23456
4.2 文件内容修改
文件对应的是硬盘空间,硬盘不能修改对应着文件本质也不能修改,那我们看到文件的内容可以修改,是如何实现的呢?
大致的思路是将硬盘中文件内容读入内存,然后在内存中修改完毕后再覆盖回硬盘具体的实现方式分为两种:
方式一:文本编辑采用的就是这种方式
- 实现思路:将文件内容发一次性全部读入内存,然后在内存中修改完毕后再覆盖写回原文件
- 优点: 在文件修改过程中同一份数据只有一份
- 缺点: 会过多地占用内存
with open('c.txt',mode='rt',encoding='utf-8') as f:
res=f.read()
data=res.replace('alex','dsb')
print(data)
with open('c.txt',mode='wt',encoding='utf-8') as f1:
f1.write(data)
方式二:
- 实现思路:以读的方式打开原文件,以写的方式打开一个临时文件,一行行读取原文件内容,修改完后写入临时文件...,删掉原文件,将临时文件重命名原文件名
- 优点: 不会占用过多的内存
- 缺点: 在文件修改过程中同一份数据存了两份
import os
with open('c.txt', mode='rt', encoding='utf-8') as f, \
open('.c.txt.swap', mode='wt', encoding='utf-8') as f1:
for line in f:
f1.write(line.replace('alex', 'dsb'))
os.remove('c.txt')
os.rename('.c.txt.swap', 'c.txt')
# 验证
f = open('a.txt')
res = f.read()
print(res)
标签:文件,utf,encoding,mode,操作,txt,open
From: https://www.cnblogs.com/lkztrovo-lsh/p/17586699.html