10.1打开文件
打开文件使用的是内置函数open
open有许多参数,在官方文档中open函数的定义如下:
open(file,mode=“r”,buffering=-1,encoding=None,errors=None,newline=None,closefd=True,opener=None)
open函数只有file函数是必须传递的,其他参数都要默认值,最简单的打开文件例子如下:
file_name = "10.1.1.py"
f = open(file_name)
10.1.1文件名模式
open函数的参数 mode十分重要,它指明了要以何种方式打开文件,使用不同的方式打开文件,即使操作相同,产生的效果也会有所不同。默认的模式是“r”,即以只读方式打开文件 可用模式如下:
书本185页
10.2文件基本操作
10.2.1读文件
如果只是希望读取整个文件并保存到一个字符串中,就可以使用read方法
f = open("222.txt")
txt = f.read()
print(txt)
read方法也可以传递参数,用于指定读取多少字符,例如:
f = open("222.txt")
txt = f.read(5)
print(txt)
10.2.2写文件
如要写文件,必须使用带“w”模式的方式打开文件。打开文件后可以使用文件对象write方法,将任意字符串写入文件中。write方法返回写入文件的字符串的长度,例如:
f = open("222.txt","w")
txt = "写入文件"
print(f.write(txt))
如果我们想在已有的文件内容后面追加内容,可以在打开文件时使用“a”模式,这样就能在文件中追加写入内容了例如:
from datetime import datetime
f = open("222.txt","a")
now = str(datetime.now())+"\n"
print(f.write(now))
每次运行这个试例,“222.txt”文件都会追加一行写入文件的时间信息
10.2.3执行读取文件
python为我们提供了一种按行读取文件内容的方法,使用readline函数可以逐行读取文件内容,例如:
f = open("222.txt","r")
print(f.readline())
print(f.readline())
readlines函数和read函数类似,都会读取整个文件,但是readlines函数会把文件内容按行切割,返回一个list列表对象。例如:
f = open("222.txt","r")
for line in f.readline():
print(line)
这个会把文件“222.txt”中的日期一行一行地打印在屏幕上。注意:readlines函数会保留结尾的换行符,所以直接print列表元素会发现每次输出都跟随一个空白行
除了使用readline和readlines方法,还能直接迭送文件对象本身,例如:
f = open("222.txt","r")
for line in f:
print(line)
10.2.4 按行写文件
python提供了writelines方法,把列表作为参数写入文件,不会添加换行符。
writelines方法接收一个参数,,这个参数必须是列表,列表的每个元素就是想写入的每行文本内容,但是我们在列表中需要自行添加换行符,例如:
f = open("222.txt","w")
lines = []
for i in range(10):
lines.append(str(i))
f.writelines(lines)
这个运行后会在文件中生成0-9十个数字 而且不会被换行。
10.2.4 关闭文件
写入文件过程中随时会出现异常,可以使用try语句捕获可能出现的相关异常,然后进行对应的处理,调用close方法来关闭文件比较好,使用如下:
f = open("222.txt","w")
f.close()
为了安全起见,使用完文件之后一定要记得关闭文件,在使用try语句出现异常后,解释器会放弃之后的语句去执行catch捕获到异常的语句,所以建议close方法在finally语句中执行,保证无论是否有异常都会执行close方法并关闭文件 如:
f = None
try:
f = open("222.txt","r")
print(f.read())
except IOError:
print("Error")
finally:
if f:
f.close()
每个打开的文件都要执行close方法关闭文件,但是有时候文件处理的逻辑比较复杂,很容易忘记关闭文件。有什么比较方便的方法能够确保文件会被关闭呢?
可以使用with语句来帮助我们自动调用close方法 如:
with open("222.txt","r")as f:
content = f.read()
print(content)
我们没有手动的去调用close函数,但是使用了with语句,会在执行完with语句之后执行close语句,让代码更简洁。
10.3StringIO和BytesIo
有时候并不需要真正地写入到文件中,只需要在内存中做读取写入即可。Python中的IO模块提供了对Str操作的StringIO函数。
要把str写入StringIO,我们要先创建一个StringIO对象,然后谢文件一样写入即可,例如:
from io import StringIO
f = StringIO()
f.write('hello')
f.write(' ')
f.write('world!!')
print(f.getvalue())
这个例子创建了StringIO对象,然后调用write方法写入数据,和文件操作几乎相同。getvalue方法用于获得写入后的str
要读取StringIO,可以先用一个str初始化StringIO,然后像读取文件一样读取,例如:
from io import StringIO
f = StringIO('Hello!\nworld!\nWelcome!')
while True:
s = f.readline()
if s == "":
break
print(s.strip())
执行结果如下:
Hello!
world!
Welcome!
StringIO的操作对象只能是str,如果要操作二进制数据,就需要使用BytesIO。
BytesIO实现在内存中读写bytes,可以先创建一个BytesIO,然后写入bytes例如:
from io import BytesIO
f = BytesIO()
f.write("您好".encode("utf-8"))
print(f.getvalue())
print(f.getvalue().decode("utf-8"))
执行结果如下:
b’\xe6\x82\xa8\xe5\xa5\xbd’
您好
注意写入的不是str,而是经过UTF-8的bytes
和StringIO类似,可以先用一个bytes初始化BytesIO,然后像读文件一样读取,例如:
from io import BytesIO
f = BytesIO(b'\xe4\xb8\xad\xe6\x96\x87')
print(f.read().decode("utf-8"))
执行结果:
中文
10.4序列化和反序列化
把变量从内存中变成可存储或传输的过程被称为序列化,可以把序列化后的内容写到磁盘或者传输到别的计算机上。反过来,我们把变量内容从序列化对象重新读取到内存的过程称为反序列化。
简单说就是:
序列化:将数据结构或者对象转换成二进制串的过程
反序列化:将序列化过程中产生的二进制串转回成数据结构或对象的过程。
10.4.1pickle模块
pickle他是标准库中的标准模块,它实现了一些基本数据的序列化和反序列化。
可以将程序中运行的对象信息保存到文件中,永久存储;可以从文件中恢复或者创建上次程序保存下来的对象。
pickle模块的dumps方法可以把对象序列化成bytes,例如:
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))
执行这个例子会打印出序列化后的bytes对象,pickle.dunos可以把任意对象序列化成bytes对象,然后永久存储。
pickle.dump方法可以帮助我们把任意对象序列化成bytes,然后直接写入到文件对象中,不需要我们在一步一步的写入文件,如:
import pickle
class Student:
def __init__(self,name,age,gender):
self.name = name
self.age = age
self.gender = gender
student1 = Student("小红",15,"女")
with open("student1.data","wb")as f:
pickle.dump(student1,f)
执行这个例子会生成student1.data,这个文件包含student1对象的信息,用文本编辑器打开这个文件会看到一堆看不懂的内容,这些都是picle保存的对象的信息。
在使用文件时自然也可以把对象从磁盘读取到内存中。我们可以先把内容读取到一个bytes对象中,然后使用pickle.loads方法获取反序列化的对象 例如:
import pickle
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)
print("性别",student1.gender)
序列化的时候可以直接写入文件对象,读取的时候当然也可以直接从文件对象中读取 例如:
import pickle
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)
print("性别",student1.gender)
这个执行结果和手动读取bytes然后使用loads方法反序列化的效果是一样的。
10.4.2 JSON序列与反序列化
json模块的序列化使用方法和pickle模块一模一样,但是pickle可以序列化任意Python对象,而json模块只能序列化10.4.1对应的类型(197页)
使用json模块序列化字典:
import json
student1 = {
"name":"小明",
"age":15,
"gender":"男"
}
print(json.dumps(student1))
注意:json模块会把中文转码为Unicode编码
其他功能和pickle模块一样,参考书本198页