1. 普通模式
1.1 文件操作说明
open()函数指定编码
open()函数访问文件时要先向操作系统发送请求,所以打开文件的编码以操作系统默认编码为准,windows默认编码为GBK。所以若open()函数不指定编码,可能会造成乱码。
open()函数不会将整个文件瞬间全部加载到内存。
python3执行代码的过程:
- 解释器找到代码文件,把代码字符串按文件头定义的编码加载到内存,转成unicode
- 把代码字符串按照语法规则进行解释
- 所有的变量字符都会以unicode编码声明
为何打开文件后要执行关闭操作:
open函数返回的是一个地址,传递给f后,f就是open函数打开文件的文件句柄。所谓的句柄就一块内存的缩印,所以这里的f其实是文件位置的内存索引。
如果打开文件后句柄一直不关闭,那么随着打开文件数量的增加,句柄量会一直增加,消耗的内存也一直增加,严重消耗系统资源。如果文件句柄保存为一个临时的变量,那么,当这个变量被回收时,文件句柄就会被关闭;但是如果其被保存在类中充当一个实例变量,那么它便一直不会被关闭,这时便不能对该文件作删除操作。
其实在程序结束时,系统会自动关闭句柄,但是直觉的关闭文件句柄是一种良好的习惯。
1.2 open()函数
- "+" 表示可以同时读写某个文件
- r+, 读写【可读,可写】,但是写的时候如果原文件存在,则会从开头开始一个个覆盖
- w+,写读【可读,可写】
- a+, 写读【可读,可写】,追加写入
- #####################################
- x, 只写模式【不可读;不存在则创建,存在则报错】
- x+ ,写读【可读,可写】
- xb
1.2.1 读(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()
1.2.2 写(w)方式打开文件
# 在文件处理的 "w" 模式下,若文件存在,则将原文件内容全部删除后,再进行写入,若文件不存在,则新建文件再进行写入 f = open("hello.txt", "w", encoding="utf-8") print(f.writable()) # 判断文件是否可写 f.write("this is my place, welcome to you") # 文件必须以字符串(str)的形式进行写入或读取 f.writelines(["name ", "age ", "gender ", "addr "]) # writelines()函数接受一个列表,并进行迭代写入 f.close()
1.2.3 追加(a)方式打开文件
# 不存在则创建,存在则追加 f = open("hello.txt", "a", encoding="utf-8") f.write("append到文件的后面") f.close()
1.2.4 其他操作
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()
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. 二进制b模式
- windodws平台中的回车为 , 而Linux和Unix平台中的回车为
- 文件默认的打开方式为 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("你好! ", encoding="utf-8")) # 这里的write中写入的内容必须为二进制形式,可以用bytes函数或者直接encode的形式编码成二进制 f.write("你的名字是什么?".encode("utf-8")) f.close() f = open("b_test.txt", "ab") f.write(bytes(" this is append ", encoding="utf-8")) # bytes函数:将对应的字符串按照一定的编码抓换成二进制 # 第一个参数接受一个str类型,第二个参数指定编码格式 f.write("the last append".encode("utf-8")) f.close() # 在python中,会统一将回车转换为 , 若想要显示windows平台中对于回车的 , 可将open函数中的 newline 选项定义为 空 "" f = open("b_test.txt", "r", encoding="utf-8", newline="") date = f.readlines() print("My_test:", date) f.close()
3. 其他方法
3.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的数量,增加效率
3.2 tell()
f = open("b_test.txt", "r+", encoding="utf-8")
print(f.tell()) # 读取光标此时的位置,现在光标处于文件开头,光标位置为0 # tell() 方法读取的光标的位置是以字节数来确定的,回车在windows平台中 为两个字节,utf-8汉字占3个字节 f.readline() print(f.tell()) # 读取一行文件内容后,现在光标位于一行的末尾
3.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个字节的字符
3.4 循环文件的方式
# 循环文件的方式: for i in f.readlines(): # 这样会一次性把文件全部加载到内存中,保存为一个列表的形式进行遍历 print(i) for i in f: # 推荐方式,这样不会一次性全部加载到内存中,只在有需要的时候慢慢加载,维持文件内容占据一片小的内存(进行读取和丢弃的循环) print(i)
4. 读取一个大文件的最后一行
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 # 偏移量过小,加大偏移量