1. 打开文件
在Python中无论是从文件中读取内容还是把内容写到文件,都需要先打开文件。打开文件使用内置函数 open
open 函数有许多参数,它的定义如下:
def open(file, mode=’r’, buffering=None, encoding=None, errors=None, newline=None, closefd=True)
open 只有file参数是必传的,其他参数都由默认值。
file_name = "1.打开文件.py"
f = open(file_name)
print(f)
1.1 文件模式
open的mode参数十分重要,它指明了要以何种方式打开文件。使用不同的方式打开文件,即使操作相同,产生的效果也会不同。
默认模式是 “r”,即以只读的方式打开文件,文件只能读但不能写。
文件模式:r、rb、r+、rb+、w、wb、w+、wb+、a、ab、a+、ab+
访问模式 | 说明 |
---|---|
r | 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。 |
w | 打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。 |
a | 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
rb | 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。 |
wb | 以二进制格式打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。 |
ab | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
r+ | 打开一个文件用于读写。文件指针将会放在文件的开头。 |
w+ | 打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。 |
a+ | 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。 |
rb+ | 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。 |
wb+ | 以二进制格式打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。 |
ab+ | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。 |
Python 读写文件时会区分二进制和文本两种方式。如果以二进制方式打开文件,内容将作为字节对象返回,不会对文本内容进行任何编码;如果以文本方式打开文件,内容将作为字符串对象返回,文件内容会根据平台相关的编码或指定了的 “encoding” 参数的编码进行解码。
1.2 文件编码
在文本方式下,如果没有指定编码,Python解释器会根据不同的系统使用不同的编码来解码文件。默认情况下,Python会调用标准库locale的getpreferredencoding方法来获取系统的默认编码,以作为文本方式解码文件内容的编码。
一般情况下,为了防止乱码,使用 UTF-8作为默认编码。
1.3 文件缓冲
缓冲的目的是减少系统 IO 的调用,只有在复合一定条件之后系统才调用 IO 写入磁盘
缓冲参数 buffering 使用用友设置缓冲策略的可选参数。
缓冲参数取值:
- 0 — 关闭缓冲;
- 1 — 选择行缓冲;
- 大于1 — 指定缓冲区大小(以字节为单位);
如果没有指定缓冲参数,则以默认缓冲策略的方式工作。缓冲取的大小为 io.DEFAULT_BUFFER_SIZE 字节,一般为 4096 或者 8192
2. 文件基本操作
2.1 读文件
readme.txt
写入文件
2.1.1 使用read读取文件内容
f = open("readme.txt")
txt = f.read()
print(txt) # 写入文件
2.1.2 read读取指定长度
f = open("readme.txt")
txt = f.read(20) # 2.读取20个字符
print(txt) # 写入文件
2.2 写文件
2.2.1 使用 “w” 模式写入文件
write 方法返回写入文件的字符串的长度
f = open("readme.txt", "w")
txt = "写入文件"
print(f.write(txt)) # 4
2.2.2 使用 “a” 模式追加文件
from datetime import datetime
f = open("append.txt", "a")
now = str(datetime.now()) + "\n"
print(f.write(now)) # 27
2.3 按行读文件
2.3.1 使用readline按行读取
文件很大、文件内容很多的时候,可以使用按行读取 readline
f = open("append.txt", "r")
print(f.readline()) # 2020-08-02 14:40:48.575777
print(f.readline()) # 2020-08-02 14:40:59.191706
2.3.2 使用 readlines 读取所有行
readlines 读取整个文件,返回一个列表
f = open("append.txt", "r")
for line in f.readlines():
print(line)
# 2020-08-02 14:40:48.575777
# 2020-08-02 14:40:59.191706
# 2020-08-02 14:42:11.297548
# 2020-11-21 15:36:30.757284
2.3.3 迭代文件对象
迭代文件对象是一种 “惰性” 的读取方式,只有迭代到需要读取的一行,才会真正执行读取操作
f = open("append.txt", "r")
for line in f:
print(line)
# 2020-08-02 14:40:48.575777
# 2020-08-02 14:40:59.191706
# 2020-08-02 14:42:11.297548
# 2020-11-21 15:36:30.757284
2.4. 按行写文件
2.4.1 使用 writelines 方法按行写入文件
使用 writelines 方法按行写入文件,writelines 接收一个列表对象,同时不会添加换行符
f = open("writelines.txt", "w")
lines = []
for i in range(10):
lines.append(str(i))
f.writelines(lines)
writelines.txt
0123456789
2.5 关闭文件
2.5.1 使用 close 关闭
文件读写完毕,或者出现异常时需要关闭。使用 close 方法
f = open("writelines.txt", "w")
f.close()
2.5.2 在 finally 中关闭
f = None
try:
f = open("readme.txt", "r")
print(f.read()) # 写入文件
except IOError:
print("Error")
finally:
f.close()
2.5.3 使用 with 自动关闭
with open("readme.txt", "r") as f:
content = f.read()
print(content) # 写入文件
3. StringIO和BytesIO
Python 对应文件的读取和写入,有时并不需要真正写入文件中,只需要在内存中做读写即可。
Python 的 IO 模块提供给了操作 str 的 StringIO 函数
3.1 StringIO
3.1.1 创建 StringIO 对象
from io import StringIO
f = StringIO()
f.write("hello")
f.write(" ")
f.write("world")
print(f.getvalue()) # hello world
3.1.2 使用字符串初始化 StringIO
f = StringIO("Hello!\nWorld!\nWelcome!")
while True:
s = f.readline()
if s == '':
break
print(s.strip())
# Hello!
# World!
# Welcome!
3.2 BytesIO
3.2.1 BytesIO 实现了内存中读写 bytes
from io import BytesIO
f = BytesIO()
f.write("您好".encode("utf-8"))
print(f.getvalue()) # b'\xe6\x82\xa8\xe5\xa5\xbd'
print(f.getvalue().decode("utf-8")) # 您好
3.2.2 使用bytes初始化 BytesIO
f = BytesIO(b'\xe6\x82\xa8\xe5\xa5\xbd')
print(f.getvalue().decode("utf-8")) # 您好
4. 序列化与反序列化
序列化就是将数据结构或者对象转换成二进制串,反序列化就是将二进制串转回成数据结构或者对象
4.1 pickle 模块
4.1.1 pickle序列化
import pickle
class Student:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
student1 = Student("小明", 15, "男")
print(pickle.dumps(student1))
# b'\x80\x04\x95G\x00\x00\x00\x00\x00\x00\x00\x8c\x08__main__\x94\x8c\x07Student\x94\x93\x94)\x81\x94}\x94(\x8c\x04name\x94\x8c\x06\xe5\xb0\x8f\xe6\x98\x8e\x94\x8c\x03age\x94K\x0f\x8c\x06gender\x94\x8c\x03\xe7\x94\xb7\x94ub.'
4.1.2 将序列化的结果保存到文件
class Student:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
student1 = Student("小红", 18, "女")
with open("student1.data", "wb") as f:
pickle.dump(student1, f)
4.1.3 反序列化
class Student:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender =gender
f = open("student1.data", "rb")
data = f.read()
student1 = pickle.loads(data)
f.close()
print("姓名", student1.name) # 姓名 小红
print("年龄", student1.age) # 年龄 18
print("性别", student1.gender) # 性别 女
4.1.4 读取文件反序列化
class Student:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
with open("student1.data", "rb") as f:
student1 = pickle.load(f)
print("姓名", student1.name) # 姓名 小红
print("年龄", student1.age) # 年龄 18
print("性别", student1.gender) # 性别 女
4.2. JSON 序列化和反序列化
json 模块的序列化使用方法和 pickle 一样,但是 pickle 可以序列化任意 Python 对象,而 json 模块只能序列化部分类型
json 可以序列化的类型: dict、list、str、int、float、True、False、None
import json
student1 = {
"name":"小明",
"age":15,
"gender":"男"
}
print(json.dumps(student1))
# {"name": "\u5c0f\u660e", "age": 15, "gender": "\u7537"}
4.2.1 json 序列化结果写入文件
student1 = {
"name":"小明",
"age":15,
"gender":"男"
}
with open("student1.json", "w") as f:
json.dump(student1, f)
4.2.2 json 反序列化
f = open("student1.json", "r")
data = f.read()
student1 = json.loads(data)
f.close()
print(student1) # {'name': '小明', 'age': 15, 'gender': '男'}
4.2.3 json 读取文件反序列化
with open("student1.json", "r") as f:
student1 = json.load(f)
print(student1) # {'name': '小明', 'age': 15, 'gender': '男'}