文件是放在磁盘上的,所以操作文件就需要磁盘的IO操作,大多数情况下文件都需要进行持久化
IO一般分为网络IO和文件IO,文件IO一般指访问磁盘(硬盘),网络IO指通过网卡把数据传过去收回来,一般IO指文件IO,访问速度比内存慢很多,遇到IO操作需要考虑是否频繁,是否影响性能
01. 文件IO常用方法
文件IO有以下方法:
方法 | 说明 |
---|---|
open | 打开文件 |
read | 读取文件内容(文本读字符和二进制读字节) |
write | 写入内容 |
close | 关闭文件 |
readline | 按行读取内容 |
readlines | 多行读取内容 |
seek | 操作指针 |
tell | 显示指针位置 |
其中最常用的方法有打开,读取,写入,关闭。文件只有在打开之后才可以进行其他操作,比如读、写(读写过程是可以循环多次的);一系列文件操作之后别忘记关闭,大家可以先想一下为什么操作完要关闭,后文也会给大家进行解释。
打开操作
python中打开文件使用如下方法,返回文件流对象,打开失败会抛出OSError异常
open(file, mode=’r’, buffering=None, encoding=None, errors=None, newline=None, closefd=True)
基本使用:
创建文件夹test,并以此为项目根目录使用pycharm打开,在test目录下创建文件hello.txt
# file对象,<class '_io.TextIOWrapper'>
f = open("hello.txt")
print(f)
# windows下输出
>>> <_io.TextIOWrapper name='hello.txt' mode='r' encoding='cp936'>
# linux下输出
>>> <_io.TextIOWrapper name='hello.txt' mode='r' encoding='UTF-8'>
content = f.read()
print(type(content), content)
>>> <class 'str'> This is hello.txt
f.close()
在不指定编码的情况下,open函数会采用当前系统的默认编码。大多数开发默认编码为UTF-8,对于windows,为了存储时编码节约,默认编码为GBK,即cp936。
open方法常用参数
- file
指打开或者要创建的文件名。如果不指定路径,则默认当前路径。
- mode
以什么模式打开文件,用来限定文件对象的操作及文本访问,比如只读,只写等。有以下模式:
描述字符 | 说明 |
---|---|
r | 只读打开,默认模式 |
w | 只写打开 |
x | 创建并写入一个新文件 |
a | 写入打开,如果文件存在,则尾部追加写 |
b | 二进制模式 |
t | 文本模式,默认模式 |
+ | 给只读只写方式提供读写能力 |
文件操作r, w, a, x,
# r模式
f = open("new.txt")
# f = open("hello.txt")
f = open("hello.txt", "r")
content = f.read()
print(content)
>>> This is hello.txt
f.write("QQQ")
f.close()
>>> 会出现什么结果?
# w模式
# 打开已有文件并写入
f = open("hello.txt", "w")
f.read()
f.close()
>>> 会出现什么结果?
f = open("hello.txt", "w")
f.write("write success!")
f.close()
>>> 查看一下hello.txt文件会有什么结果?
# 创建新文件hello1.txt
f = open("hello1.txt", "w")
f.write("This is hello1.txt")
f.close()
>>> 查看一下当前目录,是否多出一个新文件?文件内容是什么?
小结:
open方法默认只读模式r打开已存在文件
r模式下:
只读模式打开文件,使用write方法会抛异常,io.UnsupportedOperation
如果文件路径错误,会抛异常FileNotFoundError
w模式下:
只写模式打开文件,如果使用read方法会抛异常,io.UnsupportedOperation
打开已有文件,会清空文件内容
如果文件不存在,则会新建文件
# 打开已有文件
f = open("hello.txt", "x")
>>> 会出现什么现象?
f = open("hello2.txt", "x")
f.write("This is hello2.txt")
f.read()
>>> 会出现什么现象?
f = open("hello2.txt", "x")
f.write("This is hello2.txt")
f.close()
>>> 查看当前目录是否有新文件产生,如果有,看下内容
小结:
x模式下:
文件存在,会抛FileExistsError异常
文件不存在则创建新文件,只写模式,不可读取,读取则io.UnsupportedOperation异常
# a模式,打开已有文件
f = open("hello.txt", "a")
print(f.read())
>>> 会有什么现象?
f = open("hello.txt", "a")
f.write("append success")
f.close()
>>> 查看已有文件内容,发现了什么?
f = open("hello3.txt", "a")
f.write("This is hello3.txt with mode 'a' opening")
f.close()
>>> 查看当前目录有什么变化,查看文件内容
小结:
a模式下
只写打开,文件已存在,则追加写入
文件不存在,则新建文件并追加写入
文本模式t与二进制模式b
文本模式t,字符流,将文件按照指定字符编码,按照字符进行操作。open默认mode是rt,
二进制模式b,字节流,将文件按照字节打开,按照bytes类型进行操作,与字符编码无关。
# 二进制只读
f = open("hello.txt", "rb")
content = f.read()
print(type(content))
print(content)
f.close()
# 二进制只读
f = open("hello.txt", "wb")
f.write("This is mode 'wb' test")
>>> 会出现什么情况?
f = open("hello.txt", "wb")
# encode()默认utf-8编码
res = f.write("This is mode 'wb' test".encode())
print(res) # 字节数
f.close()
+模式
f = open("hello.txt", "rw")
>>> 会出现什么?
f = open("hello.txt", "r+")
# 与文件原先的内容作比较
print("1-------", f.read())
>>> 显示什么内容?
f.write("mode 'r+' test")
print("2-------", f.read())
f.close()
>>> 会出现什么现象?
f = open("hello.txt", "r+", encoding="utf-8")
f.write("mode 'r+' test".)
print(f.read())
>>> 显示什么?想一想为什么?
f.close()
f = open("hello.txt", "w+")
print(f.read())
>>> 显示什么?为什么?
f.close()
f = open("hello.txt", "a+")
f.write("a+ test")
print(f.read())
>>> 显示什么?为什么?
f.close()
f = open("hello4.txt", "x+")
f.write("x+ test")
print(f.read())
>>> 显示什么?为什么?
f.close()
小结:
+模式:
为r, w, a, x提供确实的读写功能,但获取文件对象时,仍按照原有的模式特征
+模式不能单独使用
文件指针:
既然+模式是为其他基础功能的一次增强,但是实际使用的时候,所增强的功能虽然没有报错,但也好像没有生效,这是为什么呢?此时不得不提的一个就是文件指针。文件指针,指当前字节位置。
tell()显示当前指针位置
r模式下,指针起始位置为0,
a模式下,指针起始位置为末尾EOF(End Of File),
seek(offset[, whence]),移动文件指针位置。其中offset为偏移字节量,whence指从哪里开始。
文本模式下:
whence 0 为默认值,表示从头开始,offset只能正整数
whence 1 ,表示从当前位置开始,offset只能为0
whence 2 ,表示从EOF开始,offset只能为0
f = open("tell_test.txt", "w+", encoding="utf-8")
f.write("这是tell的测试")
print("1----------", f.tell())
print("2----------", f.read())
print("3----------", f.tell())
>>> 会有输出吗?输出是什么?
f.seek(0)
print("4----------", f.tell())
print("5----------", f.read())
>>> 会有输出吗?输出是什么?
print("6----------", f.tell())
f.seek(1)
print("7----------", f.read(1))
>>> 与想象中的输出一致吗?
f.close()
小结:
文本模式支持从头开始向后偏移方式,
whence为1表示,从当前位置开始偏移,但只支持偏移为0,
whence为2表示从EOF开始偏移,只支持偏移0,
seek是按照字节偏移的,
read在文本模式下按照字符读取
二进制模式下:
whence 0 为默认值,表示从头开始,offset只能正整数
whence 1 ,表示从当前位置开始,offset可正可负
whence 2 ,表示从EOF开始,offset可正可负
f = open("tell_test.txt", "rb+")
print("1----------", f.tell())
print("2----------", f.read())
print("3----------", f.tell())
f.write(b"qwer")
f.seek(0)
f.seek(1, 1) # 从当前指针开始,向后偏移1
print("4----------", f.read())
f.seek(-1, 1) # 从当前指针开始,向前偏移1
print("5----------", f.read())
f.seek(1, 2)
f.seek(0)
f.seek(-1, 2)
print("6----------", f.read())
f.seek(0)
f.seek(100, 1)
f.seek(0)
f.seek(-100, 2)
f.close()
>>> 输出结果与预期是否一致?
小结:
二进制模式支持任意起点位置的偏移,头尾中间均可
正向seek可以超界,反向seek不可超界,会抛异常。
注:文本文件一般指使用文本直接打开的,显示的就是字符,比如txt文件;word文件也可以称作文本文件,但因为word文件有自己的格式,只能用特殊软件打开,直接用文本文件打开显示一堆乱码,这种本质上来讲是二进制文件;还有视频音频这些,使用文本打开之后,无法用文本来理解,也是二进制文件。所以只提供了两种文件模式
- buffering
一般IO设备都有缓冲区,可能还不止一个,在写入的时候,先写入缓冲区,在达到一定条件的时候再写入磁盘,因为磁盘写入太慢了,所以会采用在特定条件满足时一批一批地写入,一般缓冲区都在内存中,所以操作会很快,这个缓冲区是操作系统安排的,读取的时候,先读取缓冲区
buffer更像是队列Q,攒一批达到条件之后放行,与cache的目的是反复查询,一般来讲是一个先进先出的队列
cache里面都是key-value数据映射关系,一般放置需要反复查询的东西
- encoding
在文本模式下 最好不要使用seek中间某个位置,因为seek是按字节来的,有可能将中文拆出一部分从而报错UnicodeDecodeError,一个中文三个(utf-8)或者两个字节(GBK)
文本及bytes模式,seek时左边界不能超,右边界超的时候会在中间补ascii码0
文件指针大多数情况下用在二进制模式