Python基础(四)-文件操作
一、文件操作的流程
1)打开文件,得到文件句柄并赋值给一个变量
2)通过句柄对文件进行操作
3)关闭文件
#方式一: #打开文件,得到文件句柄并赋值给一个变量 f=open('a.txt','r',encoding='utf-8') #默认打开模式就为r #2通过句柄对文件进行操作 data=f.read() #3关闭文件 f.close() #回收操作系统打开的文件 #------------------------------------------------------ #方式二: with open('a.txt','r') as read_f,open('b.txt','w') as write_f: data=read_f.read() write_f.write(data)
注意:f=open(..)是由操作系统打开文件,由操作系统默认的编码决定(windows:gbk,linux:utf-8),若要保证不乱码,文件以什么方式存的,就要以什么方式打开
二、文件打开的模式
模式 | 描述 |
r | 只读模式,文件的指针在文件开头(默认模式,文件必须存在,不存在则抛出异常) |
rb | 以二进制格式打开一个文件,指针默认在文件开头,一般用于图片或者视频等非文本 |
r+ | 读写模式,指针在文件开头 |
w | 只写,会先清空文件内容在进行写入(不可读,不存在则创建,存在则清空内容) |
wb | 以二进制打开文件进行写入,会先清空文件内容在进行写入,一般用于图片等非文本 |
w+ | 写读,会清空文件内容在进行写入和读取 |
a | 追加写入,文件的指针在文件的结尾(不可读,不存在则创建,存在则只追加内容) |
ab | 以二进制文件打开文件进行追加,文件指针会在结尾 |
注意:
1)以b方式打开时,读取到的内容是字节类型,写入时也需要提供字节类型,不能指定编码
2)文件的相对路径与绝对路径
- 绝对路径: 从磁盘根目录开始一直到文件名
- 相对路径: 以当前目录为基准,在当前目录下相对路径就是当前文件名
2.1、只读模式(r,rb)
with open("read_file.txt",mode="r",encoding="utf-8") as f: print(f.read()) #你好 #abcdefghi
encoding:字符集,根据文件的实际保存编码进行获取数据,常用的就是 utf-8,如果不指定encoding会出现乱码,因为open()会议操作系统的默认编码格式来获取数据(gbk),而文件实际保存的格式是utf-8
with open("read_file.txt",mode="rb") as f: print(f.read()) #b'\xe4\xbd\xa0\xe5\xa5\xbd\r\nabcdefghi'
rb 模式读取出来的数据是 bytes 类型,在 rb 模式下,不能选择 encoding 字符集
rb 作用: 在读取非文本文件的时候,比如读取音频,图像,视频等信息可以用到
文件读取的方式:
f.read() #读取所有内容,光标移动到文件末尾 , 占用内存大,如果文件过大,容易导致内存崩溃 f.readline() #读取一行内容,每次读取出来的数据都会有一个\n,可以使用.strip()或print(f.readline(),end=””)去除 f.readlines() #读取每一行内容,存放于列表中 with open("read_file.txt",mode="r",encoding="utf-8") as f: print(f.readline()) print(f.readline()) #输出有空行 你好 abcdefghi ----------------------------------------------------------- with open("read_file.txt",mode="r",encoding="utf-8") as f: print(f.readline().strip()) print(f.readline().strip()) #输出去除了空行 你好 abcdefghi --------------------------------------------------------- #循环读取,每次读取一行内容,不会产生内存溢出的问题 with open("read_file.txt",mode="r",encoding="utf-8") as f: for line in f: print(line.strip()) 你好 abcdefghi
2.2、只写模式(w,wb)
写模式如果文件不存在会自动创建文件,如果文件存在会情况原有内容,在写入新内容
with open("read_file.txt",mode="w",encoding="utf-8") as f: f.write("只写模式") f.flush() #文件内容只剩下只写模式
wb 模式下,可以不指定打开文件的编码,但是在写文件的时候必须将字符串转换成 utf-8 的bytes数据
with open("read_file.txt",mode="wb") as f: f.write("wb模式".encode("utf-8")) f.flush() #文件内容:wb模式
2.3、追加模式(a,ab)
在追加模式下,写入的内容会追加在文件的结尾
with open("read_file.txt",mode="a",encoding="utf-8") as f: f.write("abc") f.write("\nabc") #使用\n换行 f.flush() wb模式abc abc
ab 模式的写法和 wb一样
with open("read_file.txt",mode="ab") as f: f.write("ab模式".encode("utf-8")) f.flush() wb模式abc abcab模式
2.4、读写模式(r+)
对于读写模式,必须是先读. 因为默认的光标是在开头,当读完了之后在进行写入
注意:在 r+ 模式下,如果读取了文件内容,无论读取内容多少,光标显示在是多少,再写入文件时都是在文件结尾写入
with open("read_file.txt",mode="r+",encoding="utf-8") as f: print(f.read()) f.write("\nr+模式") f.flush() #输出 wb模式abc abcab模式 #文件内容 wb模式abc abcab模式 r+模式
2.5、写读模式(w+)
先将文件所有的内容清空,然后写入,最后读取.但读取的内容为空
with open("read_file.txt",mode="w+",encoding="utf-8") as f: f.write("w+模式") print(f.read()) f.flush() #输出为空,因为写入之后光标在最后,后面没有内容读取 #文件内容:w+模式
2.6、追加读模式(a+)
a+ 模式下,不论是先读还是后读,都是读取不到数据的,因为光标都在最后
with open("read_file.txt", mode="a+", encoding="utf-8") as f: f.write("a+模式") print(f.read()) f.flush() #没有输出,因为光标在文件结尾 文件内容:w+模式a+模式
三、文件其他操作
3.1、光标移动seek()
格式:seek(偏移量,偏移位置)
seek(0) ==>移动光标到开头
seek(0,2) ==>移动光标到结尾
第一个参数:代表移动的偏移量
第二个参数:从哪个位置进行偏移,默认是0
- 0:表示开头
- 1:表示当前位置
- 2:表示结尾
注意:seek(n) 光标移动到 n 位置,移动的单位是 byte,如果是 UTF-8 的中文部分要是3的倍速
with open("read_file.txt",mode="r+",encoding="utf-8") as f: f.seek(0) #移动光标到开头 print(f.read()) #读取文件内容,此时光标在结尾 f.seek(0) #移动光标到开头 f.seek(0,2) #移动光标到结尾 print(f.read()) #此时读取不到内容 f.seek(0) #移动光标到开头 f.write("abc") #覆盖开头的字符 print(f.tell()) #查看光标位置 f.flush() #刷新文件到磁盘 #文件内容:12345678 ==> abc45678
3.2、光标位置tell()
with open("read_file.txt",mode="r+",encoding="utf-8") as f: print(f.tell()) f.seek(3) #光标移动3个字节 print(f.tell()) f.seek(0,2) #光标移动到结尾 print(f.tell())
3.3、文件截断truncate()
截取文件是从开头开始,到你光标位置
如果 truncate(n) 内 n 给出了位置,则就是从开头开始到 n 位置的截取
with open("read_file.txt",mode="w+",encoding="utf-8") as f: f.write("abcdef") f.seek(3) f.truncate() #截取开头到当前位置的内容 f.seek(0) print(f.read()) #abc
四、文件操作方法总结
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模式 f.readable() #文件是否可读 f.writable() #文件是否可读 f.closed #文件是否关闭 f.encoding #如果文件打开模式为b,则没有该属性 f.flush() #立刻将文件内容从内存刷到硬盘 f.name
注意:
1)read(3)
- 文件打开方式为文本模式时,代表读取3个字符
- 文件打开方式为b模式时,代表读取3个字节
2)其余的文件内光标移动都是以字节为单位如seek,tell,truncate
五、文件操作需求
5.1、大文件读取最后一行(日志文件)
#日志文件 2016/12/25 a 2016/12/26 b 2016/12/27 c 2016/12/28 a 2016/12/29 d 2016/12/30 s f=open('日志文件','rb') for i in f: offs=-10 while True: f.seek(offs,2) data=f.readlines() #readlines获取的是一个列表 if len(data) > 1: #列表的长度说明不只获取了最后一行 print('文件的最后一行是%s' %(data[-1].decode('utf-8'))) break offs*=2 #文件的最后一行是2016/12/30 s
5.2、文件的修改
文件的数据是存放于硬盘上的,因而只存在覆盖、不存在修改这么一说,我们平时看到的修改文件,都是模拟出来的效果,具体的说有两种实现方式:
方式一:将硬盘存放的该文件的内容全部加载到内存,在内存中是可以修改的,修改完毕后,再由内存覆盖到硬盘(word,vim,nodpad++等编辑器)
import os with open("a.txt",mode="r",encoding="utf-8") as read_f,\ open(".a.txt.swap","w") as write_f: data = read_f.read() #全部读入内存,如果文件很大,会很卡 data = data.replace("aaa","bbb") #在内存中修改 write_f.write(data) #一次性写入新文件 os.remove("a.txt") os.rename(".a.txt.swap","a.txt")
方式二:将硬盘存放的该文件的内容一行一行地读入内存,修改完毕就写入新文件,最后用新文件覆盖源文件
import os with open("a.txt",mode="r",encoding="utf-8") as read_f,\ open(".a.txt.swap","w") as write_f: for line in read_f: line = line.replace("aaa","bbb") write_f.write(line) os.remove("a.txt") os.rename(".a.txt.swap","a.txt")
-------------------------------------------
个性签名:独学而无友,则孤陋而寡闻。做一个灵魂有趣的人!