目录
一、前期了解
1.操作文件了解
- 应用程序运行过程中产生的数据最先都是存放于内存中的,若想永久保存下来,必须要保存于硬盘中。
- 应用程序若想操作硬件必须通过操作系统,而文件就是操作系统提供给应用程序来操作硬盘的虚拟概念,用户或应用程序对文件的操作,就是向操作系统发起调用,然后由操作系统完成对硬盘的具体操作。
文件打开基本流程
1. 打开文件,由应用程序向操作系统发起系统调用open(...),操作系统打开该文件,对应一块硬盘空间,并返回一个文件对象赋值给一个变量f
f=open('a.txt','r',encoding='utf-8') #默认打开模式就为r
2. 调用文件对象下的读/写方法,会被操作系统转换为读/写硬盘的操作
data=f.read()
3. 向操作系统发起关闭文件的请求,回收系统资源
f.close()
- 调用 open() 方法打开文件:open() 方法会根据传入的参数创建一个文件对象(f),并返回该文件对象的引用。该方法的执行过程涉及到以下几个主要步骤:
-
- 检查文件名是否存在,如果不存在,则会抛出 FileNotFoundError 异常。
- 检查文件权限是否满足操作要求,如果不满足,则会抛出相应的异常。
- 创建并返回一个文件对象,该对象会缓存文件的状态和位置等信息。
- 进行文件读写操作:可以使用文件对象提供的方法进行文件读写操作,如 read()、write()、seek() 等。在进行文件读写操作时,文件指针会根据读写位置进行相应的移动。每次读写后,文件指针都会指向下一个位置。
- 关闭文件:在文件读写操作结束后,必须调用文件对象的 close() 方法关闭文件,以释放文件资源和内存。
- 释放文件对象:当文件对象被垃圾回收机制回收时,会自动调用 close() 方法释放文件资源。
总之,Python 文件操作的内部流程主要是通过打开文件、进行读写操作和关闭文件等步骤来完成的。在进行文件操作时,要注意及时关闭文件,避免因为文件资源未释放而导致程序出错。
插图:文件对象
资源回收与with上下文管理
- with 的作用:with 能够保证代码在执行完成后,自动执行垃圾回收机制,并自动执行 close()来关闭文件
- 手动回收:打开一个文件包含两部分资源:
-
- 应用程序的变量f和操作系统打开的文件。
- 在操作完毕一个文件时,必须把与该文件的这两部分资源全部回收
1. f.close() #回收操作系统打开的文件资源
2. del f #回收应用程序级的变量
其中del f一定要发生在f.close()之后,否则就会导致操作系统打开的文件无法关闭,白白占用资源,
- 使用 with 上下文管理器
-
- python提供了 with 关键字来帮我们管理上下文,因为python自动的垃圾回收机制决定了我们无需考虑del f,或者在操作完毕文件后,很容易忘记使用f.close(),使用 with 关键字就可以解决这个问题
1.with open(r'file.txt', 'r') as f:
# 执行文件读取操作
在 with 语句中打开文件时,当退出 with 语句块时,文件对象将自动调用 close() 方法,释放文件资源。
使用 with 就等于使用了 f=open,as 后面去跟的是别名,就可以说是句柄
双引好外面跟上 r 是为了防止转义
2.语法格式:with open(r'a.txt','r',encoding='utf-8') as f:
2.1.在执行完子代码块后,with 会自动执行f.close()
with open('a.txt','w') as f:
pass
2.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)
二、Python 操作文件
Python 中的文件操作非常重要,可以用于读写文件、复制文件、删除文件等操作。
在 Python 中,使用内置的 open() 函数打开文件,并提供一些方法来进行读写、关闭等操作。
1.打开文件
使用 open() 方法可以打开一个文件,其语法为:
1.语法格式:open(‘文件路径’,‘读写模式’,‘字符编码’)
f = open('a.txt','r',encoding='utf-8')#打开文件
print(f.read())#操作文件
f.close()#关闭文件
2.f = open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
其中,file 是要打开的文件名(必须是一个字符串类型),mode 是文件打开的模式,缺省值为 'r'(只读模式)。
1.1文件操作模式
常见的文件打开模式包括:
- t 模式:text 文本
-
- r >>> rt
- w >>> wt
- a >>> at
1.它是以字符串位基本单位
2.它只能操作字符串形式
3. encoding参数必须写
- b模式:bytes二进制模式
-
- r >>> rb
- w >>> wb
- a >>> ab
1.b不能省略,必须写rb
2.它可以操作任意的数据类型:视频、音频、图片等都可以
3.encoding参数必须不能写
后面带➕代表,可读可写:r+、w+、a+
- 'r':只读模式,文件存在时可读取文件内容。
1. r只读模式: 在文件不存在时则报错,文件存在文件内指针直接跳到文件开头
with open('a.txt',mode='r',encoding='utf-8') as f:
res=f.read() # 会将文件的内容由硬盘全部读入内存,赋值给res
2. 小练习:实现用户认证功能
inp_name=input('请输入你的名字: ').strip()
inp_pwd=input('请输入你的密码: ').strip()
with open(r'db.txt',mode='r',encoding='utf-8') as f:
for line in f:
# 把用户输入的名字与密码与读出内容做比对
u,p=line.strip('\n').split(':')
if inp_name == u and inp_pwd == p:
print('登录成功')
break
else:
print('账号名或者密码错误')
- 'w':只写模式,文件不存在时会创建该文件,文件存在时先清空文件,可向文件中写入数据。
3. w只写模式: 在文件不存在时会创建空文档,文件存在会清空文件,文件指针跑到文件开头
with open('b.txt',mode='w',encoding='utf-8') as f:
f.write('你好\n')
f.write('我好\n')
f.write('大家好\n')
f.write('111\n222\n333\n')
强调:
1 在文件不关闭的情况下,连续的写入,后写的内容一定跟在前写内容的后面
2 如果重新以w模式打开文件,则会清空文件内容
- '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 模式重新打开文件,不会清空原文件内容,会将文件指针直接移动到文件末尾,新写的内容永远写在最后
# 小练习:实现注册功能:
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)
f.write(info)
- 'x':独占写模式,文件不存在时会创建该文件,如果文件已经存在则 open() 方法会抛出 FileExistsError 异常。
- 'b':二进制模式,可作为 'r'、'w'、'a' 或 'x' 模式的后缀使用,表示文件以二进制形式进行读写。用于读取或写入二进制数据,如图片、音频等
# 强调:b模式对比t模式
1、在操作纯文本文件方面t模式帮我们省去了编码与解码的环节,b模式则需要手动编码与解码,所以此时t模式更为方便
2、针对非文本文件(如图片、视频、音频等)只能使用b模式
b模式:二进制
1.能操作任何的数据类型,eg:文本,音频,视屏
2.写法:rb ab wb :此时的b不能省略
3.b模式的情况下encoding参数不能写,因为他都是字符编码的模式了encoding就没用了
rb:读写都是以二进制位单位
with open(r'a.jpeg','rb') as f: b模式的话字符编码就不要了
print(f.read()) 打印出一推二进制数
print(type(f.read())) # 输出结果为:<class 'bytes'>
wb:
with open(r'a.jpeg','rb',encoding='utf-8') as f:
f.write(b'你好') 你好前面必须加上b才可以打印出,不然出来的是乱码注释第一种编码方式
s.'你好'
f.write(s.encode(utf8)) 这是第二种编码方式
"""wb写进去了也必须rb来读,然后后面还需要跟上decode去解码
print(f.read().decode('utf8'))
"""
按照字符或字节读取:要注意他读取的数据大小
with open(r'a.txt','a',encoding='utf-8') as f:
print(f.read(1)) 当 r 模式下,read括号里面的数字代表的是字符,但是在 b 模式下read后面括号里面的代表的是字节
- '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)) # 输出结果为:<class 'str'>
with open('a.txt',mode='wt',encoding='utf-8') as f:
s='abc'
f.write(s) # 写入的也必须是字符串类型
强调:t 模式只能用于操作文本文件,无论读写,都应该以字符串为单位,而存取硬盘本质都是二进制的形式,当指定 t 模式时,内部帮我们做了编码与解码
- '+':读写模式,用于既能读取又能写入文件。
r+ w+ a+ :可读可写
在平时工作中,我们只单纯使用r/w/a,要么只读,要么只写,一般不用可读可写的模式
大前提: tb模式均不能单独使用,必须与r/w/a之一结合使用
t(默认的):文本模式
1. 读写文件都是以字符串为单位的
2. 只能针对文本文件
3. 必须指定encoding参数
b:二进制模式:
1.读写文件都是以bytes/二进制为单位的
2. 可以针对所有文件
3. 一定不能指定encoding参数
2.读写文件
在打开文件之后,可以使用 read()、write() 等方法对文件进行读写操作。
1.读文件
1.1.逐行读取文件内容
with open('file.txt', mode='r') as f:
for line in f:
print(line)
1.2.一次性读取所有内容
with open('file.txt', mode='r') as f:
content = f.read()
print(content)
'''read()是有缺陷的,如果打开文件特别大的时候就会打不开,会很慢。会导致内存溢出,因为他打开不会存在磁盘中,会先存在内存中'''
1.2.一次性读取所有行,并返回一个列表
with open('file.txt', mode='r') as f:
lines = f.readlines()
print(lines)
例子中使用了 open() 函数打开了文件,使用 with 语句操作文件,自动在处理结束后关闭文件。read() 方法将返回文件中的所有内容,可以指定读取的字符数。
2.强调:f.read()与f.readlines()都是将内容一次性读入内容,如果内容过大会导致内存溢出,若还想将内容全读入内存,则必须分多次读入,有两种实现方式:
2.1.方式一
with open('a.txt',mode='rt',encoding='utf-8') as f:
for line in f:
print(line) # 同一时刻只读入一行内容到内存中
2.2.方式二
with open('1.mp4',mode='rb') as f:
while True:
data=f.read(1024) # 同一时刻只读入1024个Bytes到内存中
if len(data) == 0:
break
print(data)
1.写入单行内容
with open('file.txt', mode='w') as f:
f.write('hello, world!\n')
"""
如果路径不存在,会新建一个文件
如果文件存在,会先清空文件中的内容,在进行写内容,就算不写东西用pass,也会清空,w模式就会直接清空
w 模式只能写string类型
"""
2.写入多行内容
with open('file.txt', mode='a') as f:
lines = ['line 1\n', 'line 2\n', 'line 3\n']
f.writelines(lines)
3. a == apppen : 追加
with open(r'a.txt','a',encoding='utf-8') as f:
f.write('内容\n')
如果路径不存在,会新建一个文件
不会清空文件内容,但是不会换行,需要自己在内容后面加\n
多行数据:括号里不可能写多行数据,需要多个write如下:
f.write('内容\n')
f.write('内容\n')
f.write('内容\n')
f.write('内容\n')
r,w,a:只能读写文档,不能读写视频音频
3.关闭文件
在使用完文件后,必须使用 close() 方法关闭文件,以释放文件资源。
f = open('test.txt', 'r')
content = f.read()
f.close()
但是,在 Python 中也可以使用 with 语句来管理文件,会自动在处理结束后关闭文件,例如:
with open('test.txt', 'r') as f:
content = f.read()
当 with 块执行结束后,Python 会自动关闭文件
4.其他文件操作
在 Python 中,还可以使用 os 模块和 shutil 模块进行文件相关的操作。例如,使用 os 模块删除一个文件:
import os
if os.path.exists('test.txt'):
os.remove('test.txt')
else:
print('The file does not exist.')
同时,os 模块还提供了其他各种文件操作方法,如重命名文件、获取文件属性等。
shutil 模块提供了对文件和目录的高级操作,例如复制文件、移动文件、创建目录等:
pythonCopy Codeimport shutil
# 复制文件
shutil.copyfile('source.txt', 'target.txt')
# 移动文件
shutil.move('source.txt', 'target.txt')
# 创建目录
os.makedirs('/path/to/new/dir')
5.对read方法做了优化
由于read是一次性读取完,可能会出现内存溢出的情况,所以,如何解决?
6.文件操作的所有内置方法
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None):打开文件并返回一个文件对象。
1.file:要打开的文件名或路径。
2.mode:文件打开模式,默认为 'r' 只读模式。其他常见模式有 'w' 只写模式、'a' 追加模式、'x' 独占模式、'b' 二进制模式和 't' 文本模式等。
3.buffering:缓冲区大小或行缓冲标志(0 表示无缓冲,1 表示行缓冲,>1 表示缓冲区大小)。
4.encoding:文件编码,用于读取和写入文本文件。默认为 None,此时使用系统的默认编码。
5.errors:错误处理方式,用于指定解码错误的处理方式。默认为 None,此时使用默认策略。
6.newline:行分隔符,用于写入文本文件时指定换行符。默认为 None,此时使用系统默认分隔符。
7.closefd: 是否关闭文件描述符。默认为 True。
8.opener:自定义文件打开器。
9.file.close():关闭文件。
offset:相对于 whence 参数的偏移量,可正可负。
whence:可选参数,表示起始位置,0 表示文件头部,1 表示当前位置,2 表示文件尾部。默认值为 0。
file.truncate(size=None):截断文件至指定大小,如果未指定大小则截断到当前位置。
f.readable() # 文件是否可读
f.writable() # 文件是否可写
f.closed # 文件是否关闭
f.encoding # 如果文件打开模式为b,则没有该属性
f.flush() # 立刻将文件内容从内存刷到硬盘
f.name
close()
1.打开文件
file = open("test.txt", mode='r')
2.关闭文件
file.close()
read() , readline() , readlines()
1.read()
1.1.打开文件
file = open("test.txt", mode='r')
1.2.读取全部内容
content = file.read()
print(content)
1.3.读取指定字节数
content = file.read(10)#读取指定大小的内容,默认读取全部内容。
print(content)
1.4.关闭文件
file.close()
2.readline()
2.1.打开文件
file = open("test.txt", mode='r')
2.2.读取一行内容
line = file.readline()#从文件中读取一行内容,如果指定参数则读取指定大小的内容
print(line)
2.3.读取多行内容
while True:
line = file.readline()
if not line:
break
print(line)
2.4.关闭文件
file.close()
3.readlines()
3.1.打开文件
file = open("test.txt", mode='r')
3.2.读取所有行并返回一个列表
lines = file.readlines()
print(lines)
3.3.关闭文件
file.close()
4.读模式
with open(r'a.txt','a',encoding='utf-8') as f:
print(f.readable()) 判断是否可具备读的条件,就是看这个文件是否可读,返回bool值
write() , writelines() , writeable()判断是否具备写的条件,返回bool值
1.write()
1.1.打开文件
file = open("test.txt", mode='w')
1.2.写入字符串
file.write("Hello World\n")#向文件写入字符串,如果文件不存在会创建文件。
file.write("Welcome to Python\n")
1.3.关闭文件
file.close()
2.writelines()
2.1打开文件
file = open("test.txt", mode='w')
2.2写入字符串列表
lines = ["Hello World\n", "Welcome to Python\n"]#向文件写入一个序列的字符串。
file.writelines(lines)
2.3.关闭文件
file.close()
3.writeable
with open(r'a.txt','a',encoding='utf-8') as f:
print(f.writeable()) 判断是否具备写的条件,返回bool值
tell()
1.打开文件
file = open("test.txt", mode='r')
2.读取文件指针位置
position = file.tell()
print(position)
3.关闭文件
file.close()
truncate()
1.打开文件
file = open("test.txt", mode='r+')
2.截断文件到指定大小
file.truncate(10)
3.读取剩余内容
content = file.read()
print(content)
4.关闭文件
file.close()
flush() 把内存中的数据立刻刷到硬盘中,因为你一开始写的数据会存储在内存中如果发生断电数据会消失
1.打开文件
file = open("test.txt", mode='w')
2.写入字符串
file.write("Hello World\n")
3.刷新缓冲区
file.flush()
4.关闭文件
file.close()
文件的操作优化
print(f.flush()) 把内存中的数据立刻刷到硬盘中,因为你一开始写的数据会存储在内存中如果发生断电数据会消失
"""文件句柄 f 支持for循环"""
with open(r'a.txt','a',encoding='utf-8') as f:
for line in f :
print(line) 把文件里面的数据一行一行打印,以后读取文件的时候都要用for循环一行一行的去读取
三、主动控制文件内指针移动
移动方法:seek() 方法,seek() 方法用于将文件内指针移动到指定位置
seek() 方法语法:
file.seek(offset, whence)
参数说明:
- offset : 需要移动的指针的相对偏移量,可以是正数、负数或零。
-
- 正数:从左往右移动
- 负数:从右往左移动
- whence : 可选参数,默认值为0
-
- 可选参数 0 : 默认的模式,该模式代表指针移动的字节数是以文件开头为参照的,whence 参数可以不写,不写就是 0(tb 两种模式都支持)
- 可选参数 1 : 该模式代表指针移动的字节数是以当前所在的位置为参照的(只支持 b 模式)
- 可选参数 2 : 该模式代表指针移动的字节数是以文件末尾的位置为参照的(只支持 b 模式)
- GBK编码:一个汉字占两个字节 。UTF-8编码:一个汉字占三个字节,不常用汉子占 4 个
强调:其中 0 模式可以在 t 或者 b 模式使用,而 1 跟 2 模式只能在 b 模式下用
1.打开文件
file = open("test.txt", mode="r")
2.移动指针到文件开头
file.seek(0)
3.读取前5个字符
content = file.read(5)
print(content)
4.移动指针到第10个字符处
file.seek(10, 0)#使用 seek(10, 0) 将文件指针移动到第10个字符处,然后使用 read() 读取从第10个字符开始的全部内容剩余内容
content = file.read()#读取从第10个字符开始,剩余的全部内容
print(content)
5.关闭文件
file.close()
# 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模式的使用
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
# 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='')
四、 文件的修改
# 文件a.txt内容如下
张一蛋 山东 179 49 12344234523
李二蛋 河北 163 57 13913453521
王全蛋 山西 153 62 18651433422
# 执行操作
with open('a.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、内存中的数据是可以修改的
1.文件修改方式一
# 实现思路:将文件内容发一次性全部读入内存,然后在内存中修改完毕后再覆盖写回原文件
# 优点: 在文件修改过程中同一份数据只有一份
# 缺点: 会过多地占用内存
with open('db.txt',mode='rt',encoding='utf-8') as f:
data=f.read()
with open('db.txt',mode='wt',encoding='utf-8') as f:
f.write(data.replace('kevin','SB'))#置换目标字符串.replace('要被置换对象','置换后新的字符',[,次数])
2.文件修改方式二
# 实现思路:以读的方式打开原文件,以写的方式打开一个临时文件,一行行读取原文件内容,修改完后写入临时文件...,删掉原文件,将临时文件重命名原文件名
# 优点: 不会占用过多的内存
# 缺点: 在文件修改过程中同一份数据存了两份
import os
with open('db.txt',mode='rt',encoding='utf-8') as read_f,\
open('.db.txt.swap',mode='wt',encoding='utf-8') as wrife_f:
for line in read_f:
wrife_f.write(line.replace('SB','kevin'))
os.remove('db.txt')
os.rename('.db.txt.swap','db.txt')
3.小练习:实现动态查看最新一条日志的效果
import time # tail -f a.txt
with open('access.log', mode='rb') as f:
f.seek(0, 2) # 直接把光标移动到了末尾
while True:
line = f.readline() # 读取一行数据
if len(line) == 0:
# 没有内容
time.sleep(1) # 睡眠 1 秒
else:
print(line.decode('utf-8'), end='')