open(pathname) 打开文件
模式 | 描述 |
r | 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。 |
rb | 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。 |
r+ | 打开一个文件用于读写。文件指针将会放在文件的开头。 |
rb+ | 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。 |
w | 打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
wb | 以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
w+ | 打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
wb+ | 以二进制格式打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
a | 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
ab | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
a+ | 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。 |
ab+ | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。 |
- 如果要打开的文件和当前py文件在同一目录,那么使用相对路径即可,否则使用绝对路径。
- 如果不指定编码方式,默认使用操作系统当前的编码,而不是使用python3的默认编码utf-8。比如Windows下默认gbk编码,而python3默认utf-8,如果不指定编码方式打开文件,读文件时解码报错。操作磁盘数据的时候一定要注意编码方式,编码和解码使用同一种方式才不会报错。
f = open(‘txt’, encoding=’utf-8’) data = f.read() print(data) f.close()
- 文件操作完之后要关闭,因为打开文件就相当于把文件内容从磁盘加载到内存中,如果不关闭,内存就会一直被占用。
- 打开文件的权限 r w a 如果不指定默认读权限打开文件
- readlines() 可以打印出换行符,以列表形式读出所有行。
- 在读文件的时候,会有一个指针指向读到的位置,使用f.read()相当于全部读完了,指针直接移到了文件末尾,再读文件就读不到内容了。
- 如果仅以w写模式打开文件,如果文件不存在则新建文件并打开;如果文件存在,则清空文件并打开。 — 得到的都是一个空文件。
- 如果写文件时需要换行,应手动添加 \n;
f.write() # 字符串形式写 f.writelines() # 列表的形式写
- 在文件中,所有内容都是字符的形式(都是字符串),所以不管读还是写,都只能读出或写入字符串,不能写入数字类型int。
- ‘a’模式 – 追加写的方式打开文件(可读可写)
在文件末尾写入数据,正常情况下我们以w模式打开文件,指针是指在文件开始的位置,当我们写入数据的时候就把原来文件头部数据覆盖了,而a模式打开可以在文件末尾追加。这里要注意,在文件最后的位置写而不代表在文件最后一行写入。 - ‘x’模式: 只写模式打开,不存在则创建,存在则报错
- 注意:文件没有修改这一概念,只有覆盖,磁盘上的文件是无法修改的,我们说的修改是指用新的数据覆盖原来的数据。实际上,我们打开一个文件,操作系统会把文件加载到内存中,我们在内存中是可以修改文件内容的,修改完当我们保存到磁盘的时候,操作系统会用修改后的文件内容去覆盖掉磁盘上原来的文件。我们在Linux中会有一个.swap交换文件,修改的文件实际上就是新建了个.swap文件,当保存文件的时候会用.swap文件覆盖原来的文件。我们使用vim打开文件,实际上就是把文件加载到内存中去修改,当文件较大的时候,打开的会非常慢,而cat查看文件不同,它不会加载到内存,所以查看的速度很快。
- with
二进制打开文件
- rb wb – 以二进制的方式打开文件,只是以二进制方式处理文件,而不是说把文件改成二进制,在Linux中没有影响,因为Linux中默认文件处理就是二进制方式。
- 以二进制方式打开文件的时候,就不能指定编码了,因为本身编码解码方式就是把字符解释成二进制的方式,既然以二进制操作文件,就没有所谓的编码解码了。
- 通过rb读文件时,读出的都是二进制,中文字符都变成了十六进制表示的编码,如果我们要看字符原来的样子,我们可以使用.decode()方法进行解码,得到字符,这里需要指定解码方式,解码方式必须和磁盘文件保存的编码方式一致。
f = open(‘txt’, ‘rb’) data = f.read() print(data.decode(‘utf-8’))
- 通过’wb’写文件,不能直接写字符串,应该写入二进制,而字符串要想变成二进制必须要经过编码,所以在写数据时要指定编码方式,以二进制的形式写入文件。
f = open(‘txt’, ‘wb’) f.write(bytes(‘hello’, encoding=’utf-8’)) f.write(‘world’.encode(‘utf-8’))
- 为什么要用b的方式打开呢,一是因为open方法打开文件时还有个默认参数是t,也就是以文本的方式打开文件text,而很多其他类型的文件比如图片视频音频,使用t的方式是处理不了的;二是因为二进制是可以跨平台的,因为不管Windows还是Linux/Unix,所有文件最终都是二进制形式存储的,所以二进制是可以跨平台的。(Linux下默认就是二进制)
回车换行符
- Windows下回车换行是 \r\n 两个字符,通过open的b方式打开,通过read方法就可以读出来。或者不通过b方式打开,在open中加一个newline=’’也可以显示出 \r 字符,否则默认是看不到 \r 的,只能看到 \n。这是因为,我们的文件可能来自Linux、Windows等不同平台,不同平台的回车换行符是不一样的,python会统一把回车换行转换成 \n。newline=’’就表示告诉python,不要帮我转换,就按照原来的样子帮我打开。Linux下回车换行是 \n 一个字符。
#以下在都是Windows平台,Linux平台回车换行本来就是\n #看不到\r只能看到\n f = open(‘txt’, ‘r’, encoding=‘utf-8’) print(f.readlines()) #可以看到\r\n f = open(‘txt’, ‘rb’) print(f.read ()) f = open(‘txt’, ‘r’, encoding=‘utf-8’, newline=’’) print(f.readlines())
文件操作
- .flush() 把内存中的数据刷新到磁盘
- .tell() 当前读写的位置,读写位置指针、光标的位置,按字节计算
- .seek() 移动读写位置,按字节的方式移动,默认从文件头开始算
只要不是read方法,其他方法对读写位置(光标)的移动都是以字节为单位,read是以字符的方式移动。
f.seek(2) #光标向下移动2个字节 f.read(2) #读取两个字符(’你好’是两个字符,utf-8编码时占6字节) f.seek(20) print(f.tell()) #– f.tell() = 20 f.seek(3) print(f.tell()) #– f.tell() = 3,注意是3而不是23 #seek移动的字节数默认从文件头开始算
- seek有三种模式
seek(num,0) # 默认方式,绝对位置,相对于文件头移动num字节 seek(num,1) # 相对位置,相对于上一次光标位置移动num字节 seek(-num,2) # 从文件尾部移动,从文件尾部往前移动num字节(要注意回车换行符\r\n),实际上就是倒着移动
需求:查看日志文件的最近一条记录(最后一行)
f = open(‘log’, ‘rb’) data = f.readlines() print(data[-1].decode(‘utf-8’)) #把整个文件读成列表放入内存 – 耗用内存,效率低 f = open(‘log’, ‘rb’) #如何循环文件 # for i in f.readlines() #按行的方式把整个文件读到内存 for i in f: #一次取一行,需要的时候才去取 offs = -10 while True: f.seek(offs, 2) data = f.readlines() if len(data) > 1: #列表长度大于1说明包含换行符,读多了 print(‘文件最后一行是%s’ %(data[-1].decode(‘utf-8’))) break offs *= 2
- 使用seek方法1、2的方式移动光标,必须要以二进制b的方式open打开文件,否则报错。
- .truncate() 截断,是一种写文件操作
f = open(‘txt’, ‘r+’, encoding=‘utf-8’, newline=’’) #可以通过r+, a+等等方式打开,只要保证有写权限即可 #不能通过w或w+方式打开,因为w会把原文件清空,得到的是空文件 #截断是一种写操作,把原文件截断为指定字节数,截断空文件没有意义 f.truncate(10) #截取10字节