Python文件操作
1. 普通模式
1.1 文件操作说明
1)open()函数指定编码
open()函数访问文件时要先向操作系统发送请求,所以打开文件的编码以操作系统默认编码为准,windows默认编码为GBK。
若open()函数不指定编码,可能会造成乱码。
open()函数不会将整个文件瞬间全部加载到内存。
2)python3执行代码的过程
- 解释器找到代码文件,把代码字符串按文件头定义的编码加载到内存,转成unicode
- 把代码字符串按照语法规则进行解释
- 所有的变量字符都会以unicode编码声明
3)为何打开文件后要执行关闭操作
open函数返回的是一个地址,传递给 f 后,f 就是open函数打开文件的文件句柄。所谓的句柄就一块内存的索引,所以这里的 f 其实是文件位置的内存索引。
如果打开文件后句柄一直不关闭,那么随着打开文件数量的增加,句柄量会一直增加,消耗的内存也一直增加,严重消耗系统资源。
如果文件句柄保存为一个临时的变量,那么,当这个变量被回收时,文件句柄就会被关闭;但是如果其被保存在类中充当一个实例变量,那么它便一直不会被关闭,这时便不能对该文件作删除操作。
其实在程序结束时,系统会自动关闭句柄,但是自觉的关闭文件句柄是一种良好的习惯。
1.2 open()函数
1)打开文件的方式
- r, w, a
- "+" 表示可以同时读写某个文件
- r+, 读写【可读,可写】,但是写的时候如果原文件存在,则会从开头开始一个个覆盖
- w+,写读【可读,可写】
- a+, 写读【可读,可写】,追加写入
- #####################################
- rb, wb, ab
- #####################################
- x, 只写模式【不可读;不存在则创建,存在则报错】
- x+ ,写读【可读,可写】
- xb
2)读(r)方式打开文件
# 不存在则报错 f = open("file.txt", encoding="utf-8") # open函数可以指定编码的格式 date = f.read() # 这里的read函数是以每一个字符的方式读取文本的 print(date) f.close() # 文件访问结束时一定要进行关闭操作 f = open("file.txt", "r", encoding="utf-8") print(f.readable()) # readable()可以用来判断文件是否可读 print(f.readline(), end="") # readline()可以读取一行文件内容,但是每一行内容后面都会被自动添加上一个换行符 print(f.readline(), end="") # 可以将print()函数的end参数指定为空,以消除readline函数中自动添加上的换行符 print(f.readlines()) # readlines()函数将每一行的内容后面添加一个换行符后保存到一个列表中 f.close()
3)写(w)方式打开文件
# 在文件处理的 "w" 模式下,若文件存在,则将原文件内容全部删除后,再进行写入,若文件不存在,则新建文件再进行写入 f = open("hello.txt", "w", encoding="utf-8") print(f.writable()) # 判断文件是否可写 f.write("this is my place,\n welcome to you") # 文件必须以字符串(str)的形式进行写入或读取 f.writelines(["name\n", "age\n", "gender\n", "addr\n"]) # writelines()函数接受一个列表,并进行迭代写入 f.close()
4)追加(a)方式打开文件
# 不存在则创建,存在则追加 f = open("hello.txt", "a", encoding="utf-8") f.write("append到文件的后面") f.close()
5)其他操作
f1 = open("file.txt", "r", encoding="utf-8") date = f1.read() f1.close() f2 = open("welcome.txt", "r+", encoding="utf-8") # r+ 模式表示读写模式,可读、可写,但文件必须事先存在 # r+模式中,若文件存在,则会从文件开头开始一个个覆盖 f2.write(date[1:]) f2.close()
6)路径
open('C:\Users\Meet') #这样程序是不识别的
解决方法一: open('C:\\Users\\Meet') #这样就成功的将\进行转义 两个\\代表一个\ 解决方法二: open(r'C:\Users\Meet') #这样相比上边的还要省事,在字符串的前面加个小r也是转义的意思
1.3 with open() as ...
# 使用with···as···的格式来进行文件操作可以不用在末尾关闭文件 # 若要将一行的代码截断到第二行显示,可以在第一行的末尾加上一个反斜杠 with open("file.txt", "r", encoding="utf-8") as f3, \ open("welcome.txt", "r+", encoding="utf-8") as f4: date = f3.read() f4.write(date)
2. 读写模式&写读模式
2.1 读写模式(r+)
读写模式必须是写读后写,因为光标默认在开头位置,当读完了以后再进行写入。
在 r+ 模式下,如果读取了内容,不论读取内容多少,光标显示的是多少,再写入。
f1 = open('shit.txt',mode='r+',encoding='utf-8') msg = f1.read() f1.write('朕,一统天下') f1.flush() f1.close() print(msg) # 正常的读取之后, 写在结尾
2.2 写读模式(w+)
w+ 模式下,是把文件清空了再写,很少用。
f1 = open('shit.txt',mode='w+',encoding='utf-8') f1.write('hehe') msg = f1.read() f1.flush() f1.close() print(msg)
3. 二进制b模式
- windodws平台中的回车为 \r\n , 而Linux和Unix平台中的回车为 \n
- 文件默认的打开方式为 rt 的方式, t 表示文本方式
- 字符串和字节之间的转换
- 字符串-----> encode -----> bytes
- bytes -----> decode -----> 字符串
f = open("b_test.txt", "rb") # 这种以二进制方式打开文件的的方式不能指定编码 date = f.read() print(date) print(date.decode("utf-8")) # 将二进制的数据流解码成utf8格式的文本内容 f.close() f = open("b_write.txt", "wb") # f.write(bytes("你好!\n", encoding="utf-8")) # 这里的write中写入的内容必须为二进制形式,可以用bytes函数或者直接encode的形式编码成二进制 f.write("你的名字是什么?".encode("utf-8")) f.close() f = open("b_test.txt", "ab") f.write(bytes("\nthis is append\n", encoding="utf-8")) # bytes函数:将对应的字符串按照一定的编码抓换成二进制 # 第一个参数接受一个str类型,第二个参数指定编码格式 f.write("the last append".encode("utf-8")) f.close() # 在python中,会统一将回车转换为 \n , 若想要显示windows平台中对于回车的 \r\n , 可将open函数中的 newline 选项定义为 空 "" f = open("b_test.txt", "r", encoding="utf-8", newline="") date = f.readlines() print("My_test:", date) f.close()
4. 其他方法
4.1 flush()
f = open("b_test.txt", "r+", encoding="utf-8") print(f.closed) # f.closed 判断文件是否关闭 print(f.encoding) # f.encoding 显示文件打开的编码 print(f.name) # f.name 显示文件名 f.flush() # f.flush() 函数将数据写入到磁盘中,因为数据一般不会立即写入磁盘, # 而是先保存到(缓冲)buffer中,到达一定的数量或时间时, # 会统一写入到磁盘中,这样会增加减少io的数量,增加效率
4.2 tell()
f = open("b_test.txt", "r+", encoding="utf-8")
print(f.tell()) # 读取光标此时的位置,现在光标处于文件开头,光标位置为0 # tell() 方法读取的光标的位置是以字节数来确定的,回车在windows平台中 \r\n 为两个字节,utf-8汉字占3个字节 f.readline() print(f.tell()) # 读取一行文件内容后,现在光标位于一行的末尾
4.3 seek()
f = open("b_test.txt", "r+", encoding="utf-8") # 除read()外,其余文件操作中处理光标移动的方法都是以字节为单位如tell() 、 seek() 、 truncate()等 # 偏移量可以为负数,表示向前偏移 f.seek(6, 0) # seek()函数的第一个参数表示偏移量,第二个参数有3个选项:
0 表示绝对位置
1 表示相对于当前位置
2 表示文件末尾 # 当seek的第二个参数为2时(从末尾开始seek), 前面的偏移量必须为负数,倒着去seek # 注意:对于非二进制的文本文件,不允许使用seek的偏移定位,只能使用全局定位 date = f.readline() print(date) f.close() f.truncate(20) # 截取从光标位置开始计数的20个字节的字符
4.4 循环文件的方式
# 循环文件的方式: for i in f.readlines(): # 这样会一次性把文件全部加载到内存中,保存为一个列表的形式进行遍历 print(i) for i in f: # 推荐方式,这样不会一次性全部加载到内存中,只在有需要的时候慢慢加载,维持文件内容占据一片小的内存(进行读取和丢弃的循环) print(i)
5. 读取一个大文件的最后一行
f = open("huge_file.txt", "rb") for i in f: # 对文件内容进行小内存循环迭代 line_length = -20 # 指定一个初始的seek长度 while True: f.seek(line_length, 2) # 将光定位到结尾的倒数第line_length个字节的位置 date = f.readlines() # 将readlines读取到的内容保存到一个列表中 if len(date) > 1: # 若列表中的元素个数大于1,表示此次readlines读取到了完整的最后一行和不完整的倒数第二行 print("最后一行的内容为:", date[-1]) # 文件最后一行的内容保存在列表的倒数第一个元素 break line_length *= 2 # 偏移量过小,加大偏移量