应用程序运行过程中产生的数据最先都是存放于内存中的,若想永久保存下来,必须要保存于硬盘中。应用程序若想操作硬件必须通过操作系统,而文件就是操作系统提供给应用程序来操作硬盘的虚拟概念,用户或应用程序对文件的操作,就是向操作系统发起调用,然后由操作系统完成对硬盘的具体操作。
文件操作的基本流程
# 1. 打开文件,由应用程序向操作系统发起系统调用open(...),操作系统打开该文件,对应一块硬盘空间,并返回一个文件对象赋值给一个变量f f=open('a.txt','r',encoding='utf-8') #默认打开模式就为r # 2. 调用文件对象下的读/写方法,会被操作系统转换为读/写硬盘的操作 data=f.read() # 3. 向操作系统发起关闭文件的请求,回收系统资源 f.close()
打开一个文件包含两部分资源:应用程序的变量f和操作系统打开的文件。在操作完毕一个文件时,必须把与该文件的这两部分资源全部回收,回收方法为:
1、f.close() #回收操作系统打开的文件资源 2、del f #回收应用程序级的变量
其中del f一定要发生在f.close()之后,否则就会导致操作系统打开的文件无法关闭,白白占用资源, 而python自动的垃圾回收机制决定了我们无需考虑del f,这就要求我们,在操作完毕文件后,一定要记住f.close(),虽然我们如此强调,但是大多数读者还是会不由自主地忘记f.close(),考虑到这一点,python提供了with关键字来帮我们管理上下文
# 1、在执行完子代码块后,with 会自动执行f.close() with open('a.txt','w') as f: pass # 2、可用用with同时打开多个文件,用逗号分隔开即可 with open('a.txt','r') as read_f,open('b.txt','w') as write_f: data = read_f.read() write_f.write(data)
文件操作模式
只读模式
r模式
只能进行读不能进行别的操作
f = open('a.txt',mode='r',encoding='utf-8') content = f.read() print(content) f.close() # open中第一个参数放入的是要打开的文件名字,第二个参数是要对这个文件进行的操作,第三参数是用什么编码方式打开文件中的内容
f 可写成任意变量等,它被称作:文件句柄,文件操作符,或者文件操作对象等。
open 是Python调用的操作系统(windows,linux,等)的功能,而windows的默认编码方式为gbk,linux默认编码方式为utf-8,所以你的文件用什么编码保存的,就用什么方法打开,一般都是用utf-8。
mode为打开方式:常见的有r,w,a,r+,w+,a+.rb,wb,ab,等,默认不写是r。
流程就是打开文件,产生一个文件句柄,对文件句柄进行相应操作,关闭文件。
rb模式
rb只读字节的模式
f = open('b.jpg',mode='rb') content = f.read() print(content) f.close()
rb 读出来的数据是bytes类型,在rb模式下,不能encoding字符集
rb的作用:在读取非文本文件的时候,比如要读取mp3,图像,视频等信息的时候就需要用到rb,因为这种数据是没办法直接显示出来的
这个字节的模式是用于传输和存储
写模式
覆盖写模式:
在写文件的时候我们要养成一个写完文件就刷新的习惯. 刷新flush()
f = open('aaa.txt',mode='w',encoding='utf-8') f.write('aaa') f.flush() f.close() 当我选择使用w模式的时候,在打开文件的时候就就会把文件中的所有内容都清空,然后在操作
注意:如果文件不存在使用w模式会创建文件,文件存在w模式是覆盖写,在打开文件时会把文件中所有的内容清空.
wb模式下,不可以指定打开文件的编辑,但是写文件的时候必须将字符串转换成utf-8的bytes数据
f = open('aaa.txt',mode='wb') msg = '你好'.encode('utf-8') f.write(msg) f.flush() # 刷新 f.close()
追加
只要是a或者ab,a+都是在文件的末尾写入,不论光标在任何位置.
在追加模式下,我们写入的内容后追加在文件的末尾
a模式如果文件不存在就会创建一个新文件
f1 = open('aaa.txt',mode='a',encoding='utf-8') msg = f1.write('bbb')
读写模式
对于读写模式,必须是先读后写,因为光标默认在开头位置,当读完了以后再进行写入.
r+模式
# 正常的读取内容, 写在文件末尾 f1 = open('aaa.txt',mode='r+',encoding='utf-8') msg = f1.read() f1.write('哈哈哈') f1.flush() f1.close() print(msg) # 错误的读取内容, 写在文件开头, 并且只读取之后的内容 f1 = open('aaa.txt',mode='r+',encoding='utf-8') f1.write('bbb') msg = f1.read() f1.flush() f1.close() print(msg)
写读模式
先将所有的内容清空,然后写入.最后读取.但是读取的内容是空的,不常用
f1 = open('bbb.txt',mode='w+',encoding='utf-8') f1.write('bbb') msg = f1.read() f1.flush() f1.close() print(msg)
追加读(a+,a+b)
a+模式下,不论是先读还是后读,都是读不到数据的
f = open('ccc.txt',mode='a+',encoding='utf-8') f.write('ccc') f.flush() msg = f.read() f.close() print(msg)
文件的相关操作
read()
read()是将文件中所有的内容都读取
f = open('aaa.txt',mode='r',encoding='utf-8') msg = f.read() f.close() print(msg)
read()可以指定我们想要读取的内容数量
f = open('aaa.txt',mode='r',encoding='utf-8') msg = f.read(3) #读取三个字符 msg1 = f.read() #后边在读就会继续向后读取 f.close() print(msg) print(msg1)
如果使用rb模式读取出来的就是字节
f = open('bbb.txt',mode='rb') msg = f.read(3) msg1 = f.read() f.close() print(msg) print(msg1)
read()的弊端就是当文件很大的时候,将文件中的内容全部读取,存放在内存中这样会导致内存奔溃
readline()
readline()读取每次只读取一行,注意点:readline()读取出来的数据在后面都有一个
f = open('aaa.txt',mode='r',encoding='utf-8') msg1 = f.readline() msg2 = f.readline() msg3 = f.readline() msg4 = f.readline() f.close() print(msg1) print(msg2) print(msg3) print(msg4
readlines()
readlines() 将每一行形成一个元素,放到一个列表中,将所有的内容全部读出来,如果文件很大,占内存,容易崩盘。
f = open('log',encoding='utf-8') print(f.readlines()) f.close()
如果有个较大的文件我们进行读取不推荐使用以下方法:
f = open('aaa',mode='r',encoding='utf-8') print(f.read()) #这样就是将文件一次性全部读取到内存中,内存容易奔溃
推荐使用的是这种方法:
f = open('aaa',mode='r',encoding='utf-8') for line in f: print(line) #这种方式就是在一行一行的进行读取,它就执行了下边的功能 print(f.readline()) print(f.readline()) print(f.readline()) print(f.readline()) f.close()
注意:读完的文件句柄一定要关闭
seek()
seek(n)光标移动到n位置,注意: 移动单位是byte,所有如果是utf-8的中文部分要是3的倍数
通常我们使用seek都是移动到开头或者结尾
移动到开头:seek(0,0) 可以看做成seek(0)
seek(6)这种如果是单数并且不是0的就是按照字节来移动光标
移动到结尾:seek(0,2) seek的第二个参数表示的是从哪个位置进行偏移,默认是0,表示开头,1表示当前位置,2表示结尾
f = open("aaa", mode="r+", encoding="utf-8") f.seek(0) # 光标移动到开头 content = f.read() # 读取内容, 此时光标移动到结尾 print(content) f.seek(0) # 再次将光标移动到开头 f.seek(0, 2) # 将光标移动到结尾 content2 = f.read() # 读取内容. 什么都没有 print(content2) f.seek(0) # 移动到开头 f.write("张国荣") # 写入信息. 此时光标在9 中文3 * 3个 = 9 f.flush() f.close() tell()
tell()
使用tell()可以帮我们获取当前光标在什么位置
f = open("aaa", mode="r+", encoding="utf-8") f.seek(0) # 光标移动到开头 content = f.read() # 读取内容, 此时光标移动到结尾 print(content) f.seek(0) # 再次将光标移动到开头 f.seek(0, 2) # 将光标移动到结尾 content2 = f.read() # 读取内容. 什么都没有 print(content2) f.seek(0) # 移动到开头 f.write("张国荣") # 写入信息. 此时光标在9 中⽂文3 * 3个 = 9 print(f.tell()) # 光标位置9 f.flush() f.close()
修改文件
文件修改: 只能将文件中的内容读取到内存中, 将信息修改完毕, 然后将源文件删除, 将新文件的名字改成老文件的名字.
import os with open("aaa", mode="r", encoding="utf-8") as f1, open("aaa_new", mode="w", encoding="UTF-8") as f2: content = f1.read() new_content = content.replace("冰糖葫芦", "⼤白梨") f2.write(new_content) os.remove("aaa") # 删除源文件 os.rename("aaa_new", "aaa") # 重命名新文件
弊端: ⼀次将所有内容进行读取. 内存溢出. 解决方案: 一行一行的读取和操作
import os with open("aaa", mode="r", encoding="utf-8") as f1, open("aaa_new", mode="w", encoding="UTF-8") as f2: for line in f1: new_line = line.replace("大白梨", "冰糖葫芦") f2.write(new_line) os.remove("aaa") # 删除源⽂文件 os.rename("aaa_new", "aaa") # 重命名新文件