Python文件读写原理
理解文件中的读取或者写入顺序要先知道对文件进行读写时它的工作模式:在python中对文件进行读写时,是依据文件中光标的位置进行读写的。
这里就要引入seek()方法:
seek(offset, whence)
offset:开始的偏移量,也就是代表需要移动偏移的字节数
whence:可选,默认值为 0。给offset参数一个定义,表示要从哪个位置开始偏移;
0 代表从文件开头开始算起
1 代表从当前位置开始算起
2 代表从文件末尾算起
例子: with open("abc.txt", "r", encoding = "utf-8") as f data = f.readline() print(data)
当我们用‘r’模式打开文件时,文件中的光标默认在第一个字符(注意是第一个字符,而不是第一行字符),当我们读取文件中的字符时,它是按照光标的位置进行读取的,对于
data = f.readline() 来说就是当光标走到第一行字符的换行符时就停止了,并返回光标走过的字符串,在txt文件内每一行字符的末尾会有一个隐藏的换行符’ ’。
此时我们对f使用seek()方法:f.seek(), 就可以改变文件内光标的位置了,以达到输出我们需要的字符的目的。
用我的理解来说seek(offset, whence)方法:
第一个参数就是把光标移动到当前的第几个字节(注意是字节,不是字符):
第二个参数就是从哪里开始(就是第一个参数解释的当前):
0 代表从文件开头开始算起。
1 代表从当前位置开始算起。
2 代表从文件末尾算起。
例如:
f.seek(3,0):就是把光标移动到文件的开头的第三个字节处。
f.seek(5,1):就是把光标移动到文件当前位置的第五个字节处。
f.seek(7,2):就是把光标移动到文件末尾的第七个字节处。
对于utf-8编码来说一个汉字占3个字节。
现在来说说对于不同的打开方式,文件光标所处的不同位置:
r:只进行读的操作,需要文件存在,进行读操作时,文件的光标在开头的第一个字节。
r+:即可读也可以写,需要文件存在。文件光标在开头的第一个字节,这里分为两种情况:
第一种:先写后读:
由于文件的光标处于开头第一个字节,这就导致了若原文件中光标的位置存在字符,则会被新写入的字符覆盖,即光标所到的位置如有字符则会被新字符覆盖,若光标所在的位置无字符,则写入新的字符。这里又产生了两种情况:
a、若此时光标走到文件末尾,若此时进行读的操作会发现什么都读不出,因为光标已经走到文件末尾了,没有字符可以被读出来。
b、若此时光标不在文件末尾,则会输出后续的字符。
在这两种情况下,若你想读出此前写入的字符你便可以用f.seek(x,x)的方法移动光标。
第二种:先读后写:
与上诉类似,光标开始处于开头第一个字节处,读的时候顺着光标的移动读出字符,若走到文件末尾进行写则不会对原有字符进行覆盖,而是追加。若是光标所在位置有字符时,进行写入则是覆盖光标所在的字符。
总结:"r’或者‘r+’模式下,文件的光标处于开头第一个字节处。
‘w’:只对文件进行全覆盖写入,若文件不存在,则会新建一个文件,文件光标处于文件开头。
‘w+’:可读可写(全覆盖),若文件不存在,则会新建一个文件,文件光标处于文件开头。这里也分为两种情况:
第一种:先读后写:由于是’w+"方式打开文件,文件内容被清除,所以什么都读不出。
第二种:先写后读:写入的字符会沿着光标为移动写入文件,写完后读会发现什么都读不出,因为此时光标处于末尾且光标指向的位置并无字符,此时可以f.seek()把光标移动到要读取的位置进行读操作。
总结:在’w’,"w+"模式下当我们open()时,原文件内容会被清除,开始时光标处于开头第一个字节处。
‘a’:对文件进行追加,若文件不存在会新建文件,文件光标位于文件末尾。
’a+‘:可读可写,若文件不存在则会新建文件,文件光标处于文件末尾。分为两种情况:
第一种:先读后写:
由于文件光标处于末尾,所以什么都读不出,此时可以f.seek(),移动光标到读取位置,读完后若要进行写入操作,不管光标处有无字符,光标都会自动移动到末尾处进行追加,若此时又要读取,则在用一次f.seek()。
第二种:先写后读:
由于文件光标处于末尾,所以写入时进行追加,此时要读取,则在用f.seek()。
总结:‘a’, "a+"模式下文件光标处于文件末尾,只要写入光标便会自动回到末尾,即只会追加。
总结:在’w’,"w"+模式下当我们open()时,原文件内容会被清除,开始时光标处于开头第一个字节处。
# encoding:utf-8# 文件读取操作fp=open("E:file.txt","r",encoding="utf-8" )data_read=fp.read()#一次性全部读完fp.seek(0,0)#游标移动到第一行,继续读,否则读取到的是空data_readlines=fp.readlines()fp.close()print(data_readlines)print(data_read)# 练习:统计文件中一行存在test的行数# 注:文件读取的时候,行的末尾包含回车换行符号 # 如果文件很大用readlines读取,小文件直接用read读取,read读取的是整个文件内容,readlines结果是listcount=0fp=open("e:file.txt","r",encoding="utf-8")lines=fp.readlines()for i in lines: if "test" in i: print(i) count+=1print(count)# read() readlines() readline()的区别# read()—当成一个字符串读出# readlines()readlines返回的是列表# readline()一行一行读文件# 如果文件很大,用read()内存不够(如运维日志几十G)# 用readline来读超大文件#原则:内存在电脑中是个稀缺的资源,如果你占用大量内存,程序肯定不是最优的,小文件:read、readlines速度更快些模式w+:先清空所有文件内容,然后写入,然后你才可以读取你写入的内容r+:不清空内容,可以同时读和写入内容。 写入文件的最开始a+:追加写,所有写入的内容都在文件的最后# a+fp=open("e:file.txt","a",encoding="utf-8")fp.write("hello python")fp.close()fp=open("e:file.txt","r",encoding="utf-8")data=fp.read()fp.close()print(data)w+#此时不需要关闭文件,w+ 可读可写(清空再写),文件不存在就创建,r+可读可写不存在报错fp=open("e:file.txt","w+",encoding="utf-8")fp.write("hello python")fp.seek(0,0)data=fp.read()fp.close()print(data)#此时不需要关闭文件,a+ 可读可写(末尾追加再写),文件不存在就创建,r+可读可写不存在报错fp=open("e:file.txt","a+",encoding="utf-8")fp.write(" hello python1")# 用来换行fp.seek(0,0)data=fp.read()fp.close()print(data)# 关于open()的mode参数:# "r":读# "w":写# "a":追加# "r+" == r+w(可读可写,文件若不存在就报错(IOError))# "w+" == w+r(可读可写,文件若不存在就创建)# "a+" ==a+r(可追加可写,文件若不存在就创建)# 对应的,如果是二进制文件,就都加一个b就好啦:# "rb" "wb" "ab" "rb+" "wb+" "ab+"seek(offset,whence)seek()offset:坐标 正数表示从前向后 负数表示从后向前 0表示最开始的游标whence:0,1,2 0表示从文件最开始位置,0,01:表示从当前位置开始,基于当前的相对位置,来重置坐标。10 seek(5,1) 10-->5,现在的坐标是152:表示从文件的末尾开始,做相对位置,来重置坐标 seek(-5,2)-->末尾向前数5个字符。注意;:1和2使用基于rb模式注意:这个文件指针的改变只是作用于"r",对"w"和"a"不会起作用,如果是"w",那么write()永远都是从开头写(会覆盖后面对应位置的内容),是"a"的话write()就永远都是从最后开始追加。fp=open("e:file.txt","rb")data=fp.readlines()print(fp.tell())fp.seek(-8,1)data1=fp.readlines()fp.close()print("data:",data)print("data1:",data1)