Python操作文件-20181121

时间:2023-03-09 20:01:40
Python操作文件-20181121

  

Python操作文件

Python操作文件和其他语言一样,操作的过程无非是先定位找到文件、打开文件,然后对文件进行操作,操作完成后关闭文件即可。

文件操作方式:对文件进行操作,主要就是读、写的方式,python有如下的几种文件操作方式:

  • 只读:r,以只读的方式打开文件,只能够读取文件,不能够对文件内容进行修改或删除,文件操作的默认操作方式,附带编码格式为utf-8
  • 只写:w,以只写的方式打开文件,操作的结果是将原文件内容清空,然后写入新的内容
  • 追加:a,以追加的方式打开文件,追加和只写一样,不能对文件进行读,可以对文件进行写,但是追加比只写会好一点,在原文件的末尾开始加入新写入的内容。
  • 读写:r+,对文件可读可写,光标在文件开头,文件的读写,都是以光标为标志位,在光标处开始读写。但是以r+打开的形式,读和写的光标是两个,这种模式是读和追加的方式,读可以任意读,写一定是从文件的最后开始写。使用的最多的方式。
  • 写读:w+,对文件可读可写,创建一个文件,开始写,写的光标是0开始,读和写的光标是反的,写光标默认在文件开始0位置,读光标默认在文件的结尾位置。写追加。
  • 追加读写:a+,追加读,
  • 二进制读:rb,网络数据传输只能用二进制来传输,以b开头,
  • 二进制写:wb,写入的时候,也要转码成二进制格式。需要编码,encode

文件的整个操作过程,都是先将文件从磁盘读取到内存中,然后通过内存操作,进行输入输出显示的。下面做一个简单的文件操作,有一个文件名为"song.txt",里面是一首歌,现在以不同的形式打开文件,进行读、写、追加的操作。文件打开是open,关闭是close。

file = open("song.txt","r",encoding="utf-8")
print(file.read())

Python操作文件-20181121

简单的文件读取操作,以r的方式,打开文件,然后将文件全部读取出来。如果文件内容比较大,一次性全部读取到内存中,会比较占用内存资源,可不可以想一种办法,一行一行的读取文件,每次取一行数据进入内存中,然后打印,这个时候就有readline了。

file = open("song.txt","r",encoding="utf-8")
print(file.readline())
print(file.readline())
print(file.readline())

Python操作文件-20181121

由于文件每行的结尾,都有一个换行符,所以在打印输出的时候,会有空行。

如果要读取的行特别多,500行上千行,可以使用for循环直接读取文件的前多少行

file = open("song.txt","r",encoding="utf-8")
for i in range(4):
  print(file.readline())

可以一次性将文件以列表的形式取出,放在内存中,使用readlines方法,文件中的每行,都是以列表元素的形式存放,通过列表的index,可以取出对应的行数。

file = open("song.txt", "r", encoding="utf-8")
data = file.readlines()
print(data,type(data))

Python操作文件-20181121

一次性将文件读取出来,对内存的消耗是很大的,尽量还是一行一行的读取,将文件变成一个可迭代的对象,然后一行一行的读取。对于迭代器,可以直接用循环进行读取。所以文件读取的标准方式是这样的:

#单行读取,迭代循环
file = open("song.txt", "r", encoding="utf-8")
for line in file:
  print(line,type(line))

Python操作文件-20181121

在这种情况下,是通过迭代循环的方式,将文件中的内容,一次取一行,然后打印出来,取出来的都是字符串类型的格式。内存中只存在一行内容。

文件的读取,是根据文件句柄光标来的,也可以认为是游标,cursor,通过tell方法,可以返回在读写过程中,光标所在文件中的位置,以字符计数。通过seek方法,可以将光标移动到想要的位置,需要指定位置,比如回到文件开始的位置,也就是0。Tell和seek可以搭配起来使用。终端设备文件不能用seek。

file = open("song.txt", "r", encoding="utf-8")
print("当前光标位置:",file.tell())
print(file.readline())
print("读取一行后,光标位置:",file.tell())
file.seek(21)
print(file.readline())
file.close()

Python操作文件-20181121

Seek和tell的使用,可以通过tell查询当前读取或写入的光标的位置,然后seek移动到从文件开始0处,到目标设置的光标处,上面就是移动到21处,在python 中汉字是3个byte,所以一定要移动的数字是3的整数倍才能使用。但是第一行读完15个汉字,光标在44,是0-45,光标移动到21,前面有0-20个byte,也就是7个汉字。

打印文件的编码方式,encoding,直接将文件的编码方式返回。打印文件句柄在内存中的编号,也就是pid,fileno,每个文件在内存中打开,都有一个内存编号。在linux中通常在写脚本时候会用到合格pid,强制关闭某个进程。

刷盘,flush,从内存刷到磁盘,强制。这个特性和文件缓存有关系,文件的读写,都需要经过缓存,当缓存中的数据容量,达到刷盘范围,或者到刷盘时间,才会将数据刷到磁盘中,如果是文件直接写到磁盘,会影响文件的读写时间,因为磁盘读写比较慢,内存缓存读写是比磁盘快的。当数据还未写入到磁盘时,机器断电,就会出现内存缓存中的数据丢失,当要求文件强一致性时,可以通过flush进行强制刷盘,将内存缓存中写入的文件,刷入到磁盘中。

主要的使用场景,就是在进度条上面,会使用flush。Sys模块。

下面简单做一个进度条的样子。

import sys,time

for i in range(10):
  sys.stdout.write("\r%s"%("#"*i))
  sys.stdout.flush()
  time.sleep(0.5)

每间隔0.5秒打印一次输出,输出之前,清除上一次的输出,每次输出强制性刷新到屏幕上展示。优化的好一点的代码如下。

import sys,time
def percent(number,total=100):#定义一个函数,用来显示百分数
  percent_number="%d"%(number/total*100)+"%"
  return percent_number

for i in range(100):
  sys.stdout.write("\r[%s%s%s]"%(("#"*i),(" "*(100-i)),percent(i)))
  sys.stdout.flush()
  time.sleep(0.5)

最后打印的结果如下图所示。

Python操作文件-20181121

解释一下,在占位符中,%d表示将结果以数字的形式。不带小数的数字。

截断,truncate,如果不带任何参数,就会清空文件,如果带上一个参数,数字,就会从文件开头开始,多少个字符之后,删除之后的所有内容。

文件修改操作

在原文件上的修改(磁盘),是直接替换了该位置上面的数据。修改只能是先将文件从磁盘加载到内存中,整个修改操作是在内存中进行的,当修改完成后,将内存中的数据写入到原文件中。内存中在原位置上出入,之后的数据就会往后顺序排,所以在内存中能实现插入。在原文件上修改,或者是在内存中修改,写入到新的文件中。打开两个文件,一个是原文件,一个是目标文件,从原文件中读取数据,替换成新数据之后,写入到目标文件中。

下面做一个简单的替换,生成一个新文件,将旧文件中的某些字段替换。

file_old = open("song.txt",'r',encoding='utf-8')
file_new = open("song_new.txt",'w',encoding='utf-8')
for line in file_old:
  if "你" in line:
    line = line.replace("你","她")
  file_new.write(line)
file_old.close()
file_new.close()

从song.txt中读取文件,然后将里面的"你",替换成"她",然后将新的数据,写入到新文件中。

而想普通编辑器vim、ue等,在用户体验上感觉都是在原文件上的修改,实际上是先将文件读取到内存中,然后对内存对象进行修改,修改完成后,以写的方式重新打开原文件,然后完成覆盖。所以保存之后是直接写到原文件中的。实现的代码可以简单写一下。整个过程中,文件是全部读取进内存中的,如果文件比较大,读取的过程会很长。

file_old = open("song.txt",'r',encoding='utf-8')
data_old = file_old.readlines()
file_old.close()
file_new = open("song.txt",'w',encoding='utf-8')
for line in data_old:
if "你" in line:
line = line.replace("你","她")
file_new.write(line)
file_new.close()