在python中如果想对硬盘中的一个文件进行操作大概可以分为三步,它的流程如下:
open函数的使用方法如下。
open(‘文件路径’,mode=‘打开文件的模式‘,encoding='文件编码方式')
'b' 二进制模式,使用二进制的方式来打开文件,注意!这个‘b’(二进制模式)是要与(r,w,a)三种模式组合使用的。(跨平台跨操作系统建议使用此模式)
'r+' 可读可写(在这种模式下,虽然可读可写,但是写的时候一定要注意,seek指针还在文件的头部,如果没有调整seek指针的位置直接开始写入,会直接开始覆盖前面写的内容(从文件头部开始),所以说,在使用r+模式的时候,一定要注意seek指针的位置,在文件的什么地方!!否则会覆盖原有内容。)
'w+' 可写可读 (这个模式一般情况下不要用,也会直接清空文件)
'a+' 末尾追加,可写可读
一.对文件对象进行操作的常用方法
读文件:
readable()用于判断文件是否可读,如果可读返回True,否则返回False。
readline() 一次读取文件的一行,返回字符串类型。
read()一次读取文件所有的内容,返回一整个字符串。
readlines()读取文件的所有内容,并把文件的每一行内容添加到一个列表里面,文件的每一行内容都将作为列表中的一个元素。
写文件:
writable():判断文件是否可写,如果可写,返回True,否则返回False。
write():在文件中写入内容,只有当文件处于可写的模式,才可以使用此方法,具体在文件的什么位置写,则取决于文件的打开模式(是r+还是a+或者是w+)还有就是取决于当前的seek指针所指向文件的什么位置。(在补充一点,使用write方法向文件内部写内容,是没有换行符的,需要手动添加个换行符,不然所有的内容都会粘到一起。)
例:f1.write('hello!\n') #\n就是换行符。
writelines():和wirte类似,都是向文件内部写入内容,和write不同的是,writelines是使用列表的形式来对文件内部写入内容,使用writelines方法,python会将列表循环,列表中的每个元素都会写入到文件中。
注意!使用writelines对文件内部写内容时,也是不带换行符的,如果给每个元素的尾部都加个换行符,那么列表中的每一个元素都是文件中的一行。
注意!!在文件中写入的内容只能是字符串,不可以是其他类型!!否则会抛出异常,就算要写入数字,那么这个数字也一定要转换成字符串类型!!!
其他操作:
close()关闭文件,当文件使用读完或者写完后一定要使用close关闭文件!(使用with语法除外,因为使用with关键字打开文件,对文件的操作结束后,会自动关闭文件)。
读完文件后不关闭,程序会一直占用系统资源。
写完文件后不关闭,会导致内存中的内容不会及时的同步到硬盘中,若想把内容彻底写到硬盘,要不然就使用close关掉文件,要不然,就使用flush方法强制把内存中的数据刷到硬盘上。
flush()将内存中没有写到硬盘上的数据,强刷到硬盘中。
encoding:显示文件打开的编码(在python2中没有这个方法,在python3中可以使用。)
tell():可以获取当前seek指针的位置。
seek(指针位置 ,模式)以字节为单位,移动seek指针,在文件中的位置。
在pyrhon中对seek指针的操作有三种模式,下面对这三种模式进行一个详细的介绍:
file.seek(n,0)#n代表了指针的位置,后面的数字0代表的是模式的序号。
file.seek(n,0):(模式0)模式0代表了,绝对位置,n为几,就会把指针移动到从文件开头开始算数的第几个字节。(在使用seek时,如果不指定模式,那么默认的模式就是0。)
比如说file.seek(3,0) 将指针移动到从文件的开头(第0个字节)开始数,三个字节的位置。
#没使用指针之前
f1 = open('seasons.lrc',mode='r')
print f1.readline()
>>>浜崎あゆみ - Seasons
#下面是使用0模式,将指针移动到文件的第3个字节,将指针移动到第3个字节以后,在去读文件,就会从指针的后面开始读文件。
f1 = open('seasons.txt',mode='r')
print f1.tell() #显示一下seek指针当前的位置
>>>0 #(位置是0,代表指针在文件的开头)
f1.seek(3,0) #(将指针移动到第三个字节处,使用0模式,绝对位置)
print f1.tell() #再次查看指针位置,可以验证指针的位置确实被移动到了第三个字节处。
>>>3
print f1.readline() #从当前指针的位置后面读取一行。
>>>崎あゆみ - Seasons
这时可能有人要问了,读文件是从指针的后面开始读的没错,但是明明把指针移动到了三个字节之后啊,为什么才跳过了一个字符?
这就需要了解什么是字符和字节了,一定要清楚这个概念!!在utf-8的字符编码中,一个汉字会占用三个字节,原来第一行的内容是“浜崎あゆみ - Seasons”,因为一个汉字占了三个字节,所以指针被向后移动了三个字节,正好是一个汉字的位置,指针被移动到了“浜”后面,读文件的话,就从这个字后面开始读, 所以显示的就是“崎あゆみ - Seasons”。(一个日文字符在utf-8字符编码中也占三个字节。)
后面在举个例子,这个例子可以明白“绝对位置”的意思。
f1 = open('seasons.lrc',mode='r')
print f1.tell() #打开文件后,指针默认的位置是0。
>>>0
f1.seek(3,0) #将指移动到文件中3个字节的位置。
print f1.tell()
>>>3
f1.seek(3,0)
print f1.tell()
>>>3
file.seek(n,1): (模式1)模式1,相对位置,n代表了指针在当前位置向后移动几个字节。
如果觉得我说的不太容易懂的话,估计看下后面的例子,就懂了。
f1 = open('seasons.lrc',mode='r')
print f1.tell() #打开文件后,指针默认的位置是0。
>>>0
f1.seek(3,1) #将指针向后移动3个字节的位置。
print f1.tell()
>>>3 #指针移动到了第3个字节的位置。
f1.seek(3,1) #这里是重点了,将指针在向后移动3个字节(在这个地方就可以比较出模式1和模式0的区别了。)
print f1.tell()
>>>6 #指针的位置在第6个字节上,这也就说明了,1模式每次移动,并不是从文件的开头开始算起,而是根据指针上次所在的位置开始向后移动。(这也就是“相对位置”的意思。)
如果还看不懂,那就看下面的补充。
最后在补充一下:
f1.seek(3,0) 是指,将指针移动到文件第3个字节的位置。(绝对位置)
f1.seek(3,1) 是指,将指针从当前位置向后移动3个字节的位置。(相对位置)
file.seek(-n,2): 以绝对位置,从文件最末尾开始,向文件的开头移动。(在使用2模式时,需要注意,指针移动的位置只能是负数,因为是从最末尾开始向前移动!)
下面是例子:
#打开一个文件,使用read方法从头读到文件的尾部,当文件被读完,指针自然就回移到文件的末尾。
f1 = open('seasons.txt',mode='r')
print f1.tell()
>>>0
f1.read()
print f1.tell()
>>>756
现在通过上面的方法已经知道,文件的最末尾是文件的第几个字节。
下面来测试下seek方法的2模式的功能是否如之前所说,从文件最末尾开始,向文件的开头移动。
f1 = open('seasons.txt',mode='r')
print f1.tell()
>>>0
f1.seek(-1,2) #使用seek的2模式,将指针从文件的最末尾向前移动1个字节
print f1.tell()
>>>755
#文件的最末尾是756,向前移动了一个字节就是755,得到了我们想要得到的效果。
其实seek方法的2模式还是比较有用的,下面就细说下seek方法的2模式。
在获取文件的倒数第1行到第N行,就可以使用seek方法的2模式。
这时可能会有人问,取出文件的最后一行,岂不是很简单的操作,只要使用readlines方法把文件都读出来,然后取最后一个元素,就可以取到最后一行了,这种方法岂不是更简单?
像这样。
f1 = open('seasons.txt',mode='r')
print f1.readlines()[-1]
>>>そして何を?つけるだろう
文件的最后一行确实被取出来了,但是,有没有想过,这种使用readlines读取文件的本质,是把文件的每一行全部读到内存中,如果这个文件特别大,比如说10个G,100G,大到当前的内存放不下,如果是这种情况,这种方法就不适用了。
下面这种方法,对于大文件就特别适用了。
f1 = open('seasons.txt',mode='r')
for i in f1: #直接for循环文件句柄,并不会一次性把文件都读到内存,而是读一行从文件中取一行。
line_bytes = -36
while True:
f1.seek(line_bytes,2)
data = f1.readlines()
if len(data) > 1:
print data[-1]
break
else:
line_bytes * 2