文章目录
IO
- Input/Output,也就是输入和输出;IO编程中,Stream(流)是一个很重要的概念
- 方式
- 同步IO
- 异步IO
- 同步和异步的区别就在于是否等待IO执行的结果;使用异步IO来编写程序性能会远远高于同步IO,但是异步IO的缺点是编程模型复杂
- 操作IO的能力都是由操作系统提供的,每一种编程语言都会把操作系统提供的低级C接口封装起来方便使用
- 此处的IO编程都是同步模式
操作目录和文件(os,os.path)
-
操作目录和文件所需的模块
os
import os print(os.name) #操作系统名称 print(os.environ) #环境变量 ...
-
更多操作见-os的源代码
操作文件和目录
-
Python的
os
模块封装了操作系统的目录和文件操作,要注意这些函数有的在os
模块中,有的在os.path
模块中 -
os.path 模块的几种常用方法
os.path.abspath(path) 返回绝对路径 os.path.basename(path) 返回文件名 os.path.commonprefix(list) 返回list(多个路径)中,所有path共有的最长的路径 os.path.dirname(path) 返回文件路径 os.path.exists(path) 路径存在则返回True,路径损坏返回False os.path.lexists 路径存在则返回True,路径损坏也返回True os.path.expanduser(path) 把path中包含的""和"user"转换成用户目录 os.path.expandvars(path) 根据环境变量的值替换path中包含的" n a m e " 和 " name"和" name"和"{name}" os.path.getatime(path) 返回最近访问时间(浮点型秒数) os.path.getmtime(path) 返回最近文件修改时间 os.path.getctime(path) 返回文件 path 创建时间 os.path.getsize(path) 返回文件大小,如果文件不存在就返回错误 os.path.isabs(path) 判断是否为绝对路径 os.path.isfile(path) 判断路径是否为文件 os.path.isdir(path) 判断路径是否为目录 os.path.islink(path) 判断路径是否为链接 os.path.ismount(path) 判断路径是否为挂载点 os.path.join(path1[, path2[, …]]) 把目录和文件名合成一个路径 os.path.normcase(path) 转换path的大小写和斜杠 os.path.normpath(path) 规范path字符串形式 os.path.realpath(path) 返回path的真实路径 os.path.relpath(path[, start]) 从start开始计算相对路径 os.path.samefile(path1, path2) 判断目录或文件是否相同 os.path.sameopenfile(fp1, fp2) 判断fp1和fp2是否指向同一文件 os.path.samestat(stat1, stat2) 判断stat tuple stat1和stat2是否指向同一个文件 os.path.split(path) 把路径分割成 dirname 和 basename,返回一个元组 os.path.splitdrive(path) 一般用在 windows 下,返回驱动器名和路径组成的元组 os.path.splitext(path) 分割路径中的文件名与拓展名 os.path.splitunc(path) 把路径分割为加载点与文件 os.path.walk(path, visit, arg) 遍历path,进入每个目录都调用visit函数,visit函数必须有3个参数(arg, dirname, names),dirname表示当前目录的目录名,names代表当前目录下的所有文件名,args则为walk的第三个参数 os.path.supports_unicode_filenames 设置是否支持unicode路径名
文件读写(open)
- 在磁盘上读写文件的功能都是由操作系统提供的,现代操作系统不允许普通的程序直接操作磁盘,所以,读写文件就是请求操作系统打开一个文件对象(通常称为文件描述符),然后,通过操作系统提供的接口从这个文件对象中读取数据(读文件),或者把数据写入这个文件对象(写文件)
open()
函数,返回值是IO对象
常见格式
- open() 函数常用形式是接收两个参数:文件名(file)和模式(mode)
open(file, mode='r')
完整格式
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
- file: 必需,文件路径(相对或者绝对路径)
- mode: 可选,文件打开模式
- buffering: 设置缓冲
- encoding: 一般使用utf8
- errors: 报错级别
- newline: 区分换行符
- closefd: 传入的file参数类型
- opener: 设置自定义开启器,开启器的返回值必须是一个打开的文件描述符
file打开模式mode
模式 | 描述 |
---|---|
t | 文本模式 (默认)。 |
x | 写模式,新建一个文件,如果该文件已存在则会报错。 |
b | 二进制模式。 |
+ | 打开一个文件进行更新(可读可写)。 |
r | 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。 |
rb | 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。一般用于非文本文件如图片等。 |
r+ | 打开一个文件用于读写。文件指针将会放在文件的开头。 |
rb+ | 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。一般用于非文本文件如图片等。 |
w | 打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
wb | 以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。 |
w+ | 打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
wb+ | 以二进制格式打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。 |
a | 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
ab | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
a+ | 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。 |
ab+ | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。 |
- 默认为文本模式,如果要以二进制模式打开,加上 b 。
file常用的函数
方法及描述 |
---|
file.close()关闭文件。关闭后文件不能再进行读写操作。 |
file.flush()刷新文件内部缓冲,直接把内部缓冲区的数据立刻写入文件, 而不是被动的等待输出缓冲区写入。 |
file.fileno() 返回一个整型的文件描述符(file descriptor FD 整型), 可以用在如os模块的read方法等一些底层操作上。 |
file.isatty()如果文件连接到一个终端设备返回 True,否则返回 False。 |
file.read(size])从文件读取指定的字节数,如果未给定或为负则读取所有。 |
file.readline(size)读取整行,包括 “\n” 字符。 |
file.readlines(sizeint)读取所有行并返回列表,若给定sizeint>0,返回总和大约为sizeint字节的行, 实际读取值可能比 sizeint 较大, 因为需要填充缓冲区。 |
file.seek(offset, whence)移动文件读取指针到指定位置 |
file.tell()返回文件当前位置。 |
file.truncate(size)从文件的首行首字符开始截断,截断文件为 size 个字符,无 size 表示从当前位置截断;截断之后后面的所有字符被删除,其中 windows 系统下的换行代表2个字符大小。 |
file.write(str)将字符串写入文件,返回的是写入的字符长度。 |
file.writelines(sequence)向文件写入一个序列字符串列表,如果需要换行则要自己加入每行的换行符。 |
注意
- 说明注意使用
open()
方法一定要保证关闭文件对象,即调用 close() 方法。
StringIO和BytesIO
- 所在模块为
IO
模块
StringIO
-
在内存中读写str
from io import StringIO f = StringIO() f.write('write string') print(f.getvalue()) # 结果 write string
from io import StringIO f = StringIO('this\nis\nstring') while True: s = f.readline() #也会读取\n if s == '': break print(s.strip()) # strip()会将\n剥掉 # 结果 this is string
BytesIO
-
在内存中读写二进制
from io import BytesIO f = BytesIO() f.write('二进制'.encode('utf-8')) # 对字符串进行编码encode为二进制 print(f.getvalue()) # 结果 b'\xe4\xba\x8c\xe8\xbf\x9b\xe5\x88\xb6'
from io import BytesIO f = BytesIO(b'\xe4\xba\x8c\xe8\xbf\x9b\xe5\x88\xb6') bytes_res = f.read() str_res = bytes_res.decode('utf-8') #对二进制进行解码decode为字符串 print(bytes_res) print(str_res) # 结果 b'\xe4\xba\x8c\xe8\xbf\x9b\xe5\x88\xb6' 二进制
序列化(pickle,json)
- 序列化所在模块
pickle
序列化
其他语言的serialization等表示同一个意思
-
序列化:从内存中变成可存储或传输的过程
- 作用对象:Python中自身的数据类型,如变量,类,对象等…
-
序列化用
pickle.dumps(待序列化变量)
,pickle.dump(待序列化变量, 文件对象)
import pickle d = dict(name='Bob', age=20) dump_res = pickle.dumps(d) #序列化,返回值是序列化的结果 print(dump_res) # 将dump结果写入文件 with open('dump_res.txt', 'wb') as f: f.write(dump_res) # 结果 b'\x80\x03}q\x00(X\x04\x00\x00\x00nameq\x01X\x03\x00\x00\x00Bobq\x02X\x03\x00\x00\x00ageq\x03K\x14u.'
import pickle d = dict(name='Bob', age=20) f = open('dump_res.txt', 'wb') dump_res = pickle.dump(d, f) #在序列化的同时,把序列的结果存在文件里 #返回值是None print(dump_res) f.close() # 结果 None
- 注意
pickle.dumps(变量)
仅仅是序列化,返回序列化的结果pickle.dump(变量, 文件对象)
是将变量进行序列化并存入文件中,返回值是None
- 注意
反序列化
-
反序列化:把变量内容从序列化的对象重新读到内存里
-
序列化用
pickle.loads(序列化后的变量)
,pickle.load(文件对象)
import pickle d = dict(name='Bob', age=20) dump_res = pickle.dumps(d) load_res = pickle.loads(dump_res) #反序列化,返回值是反序列化的结果 print(load_res) # 结果 {'name': 'Bob', 'age': 20}
import pickle with open('dump_res.txt', 'rb') as f: d = pickle.load(f) #反序列化 print(d) # 结果 {'name': 'Bob', 'age': 20}
注意
- Pickle的问题只能用于Python,并且可能不同版本的Python彼此都不兼容,因此,只能用Pickle保存那些不重要的数据,不能成功地反序列化也没关系。
Json(dumps,loads)
所在模块json
-
如果我们要在不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如XML,但更好的方法是序列化为JSON
-
JSON表示出来就是一个字符串,可以被所有语言读取,也可以方便地存储到磁盘或者通过网络传输。JSON不仅是标准格式,并且比XML更快,而且可以直接在Web页面中读取
-
JSON表示的对象就是标准的JavaScript语言的对象,JSON和Python内置的数据类型对应如下
JSON类型 Python类型 {} dict [] list “string” str 1234.56 int或float true/false True/False null None -
json
模块的dumps()
和loads()
函数是定义得非常好的接口的典范。当我们使用时,只需要传入一个必须的参数。但是,当默认的序列化或反序列机制不满足我们的要求时,我们又可以传入更多的参数来定制序列化或反序列化的规则
Json序列化基本数据类型
- 由于JSON标准规定JSON编码是UTF-8,所以我们总是能正确地在Python的
str
与JSON的字符串之间转换。
序列化
json.dumps(基本数据类型)
,json.dump(基本数据类型, 文件对象)
import json
d = dict(name='Bob', age=20)
json_dump_res = json.dumps(d) #序列化,返回值是Json格式的数据
print(json_dump_res)
# 将dump结果写入文件
with open('json_dump_res.txt', 'w') as f:
f.write(json_dump_res)
# 结果
{"name": "Bob", "age": 20}
import json
d = dict(name='Bob', age=20)
f = open('dump_res.txt', 'w')
json_dump_res = json.dump(d, f) #在序列化的同时,把序列的结果存在文件里
#返回值是None
print(json_dump_res)
f.close()
# 结果
None
反序列化
json.load(文件对象)
import json
with open('json_dump_res.txt', 'r') as f:
res = json.load(f) #反序列化,并将反序列化的结果返回
print(res)
# 结果
{'name': 'Bob', 'age': 20}
Json序列化实例对象
-
Python的
dict
对象可以直接序列化为JSON的{}
, -
不过更多时候用
class
表示对象,然后序列化实例对象
需要定制Json序列化
json.dumps(基本数据类型, default=定制序列化函数名)
json.dump(基本数据类型, default=定制序列化函数名, fp=要保存进的文件名)
- 因为默认情况下,json的dump方法不知道如何将实例变为一个JSON的
{}
对象,只需要为类专门写一个转换函数,再把函数传进去即可
- 因为默认情况下,json的dump方法不知道如何将实例变为一个JSON的
import json
class Student(object):
def __init__(self, name, age):
self.name = name
self.age = age
#自定义对象转化为json的函数,而非实例方法
def stu2dict(stu):
return {
'name':stu.name,
'age':stu.age
}
stu = Student('Alice', 20)
json_dumps_res = json.dumps(stu, default=stu2dict)#使用dumps()的 `default=定制转换函数名`
print(json_dumps_res)
# 结果
{"name": "Alice", "age": 20}
- 因为通常
class
的实例都有一个__dict__
属性,它就是一个dict
;把任意class
的实例变为dict
import json
class Student(object):
def __init__(self, name, age):
self.name = name
self.age = age
stu = Student('Alice', 20)
json_dumps_res = json.dumps(stu, default=lambda obj: obj.__dict__)
print(json_dumps_res)
# 结果
{"name": "Alice", "age": 20}
# 保存到文件中
import json
class Student(object):
def __init__(self, name, age):
self.name = name
self.age = age
#自定义对象转化为json的函数,而非实例方法
def stu2dict(stu):
return {
'name':stu.name,
'age':stu.age
}
stu = Student('Alice', 20)
with open('json_dump_obj_res.txt', 'w') as f:
json_dumps_res = json.dump(stu, fp=f, default=stu2dict)#使用dumps()的 `default=定制转换函数名`
print(json_dumps_res)
# 结果
None
反序列化
json.dumps(Json字符串,object_hook=定制反序列化函数名)
,返回值反序列化的实例对象json.dump(fp=json字符串文件,object_hook=定制反序列化函数名)
需要定制Json反序列化函数
import json
class Student(object):
def __init__(self, name, age):
self.name = name
self.age = age
#自定义jso转化为dict的函数,而非实例方法
def dict2student(s):
return Student(s['name'], s['age'])
json_str = '{"name": "Alice", "age": 12}'
json_dumps_res = json.loads(json_str, object_hook=dict2student)#object_hook=定制转换函数名
print(json_dumps_res)
# 结果
<__main__.Student object at 0x00000149AC4B9668>
# 从文件中读取
import json
class Student(object):
def __init__(self, name, age):
self.name = name
self.age = age
#自定义jso转化为dict的函数,而非实例方法
def dict2student(s):
return Student(s['name'], s['age'])
with open('json_dump_obj_res.txt', 'r') as f:
json_dumps_res = json.load(fp=f, object_hook=dict2student)#object_hook=定制转换函数名
print(json_dumps_res)
# 结果
<__main__.Student object at 0x0000020C237D34A8>
说明
pickle
用于Python特有的序列化操作,可以保存Python中任何数据类型。序列化结果使用二进制进行读写json
多用于数据交换,可以实现Json字符串与Python数据类型之间的序列化。序列化结果使用字符进行读写dumps
和loads
分别用于在内存中的序列化;dump
和load
分别用于文件中的序列化
常见的文件操作
-
一般文件打开模式只用r/w/a,一般不用**可读可写(+)**的模式
-
自动关闭文件的方式:
with
with open('te.txt',mode='r',encoding = 'utf-8') as f: f.read() pass
读操作
f.readline() # 读取一行内容,光标移动到第二行首部参数
f.readlines() # 读取每一行内容,存放于列表中,返回的结果是一个列表。
f.read(num) # 读取所有内容,执行完该操作后,文件指针会移动到文件末尾,是一个整形数值,表示一次性读入的字符数
- 文件对象 f 也是一个 可迭代对象 在遍历文件对象的时候,默认一次拿一行
f.read()
与f.readlines()
都是将内容一次性读入内容,如果内容过大会导致内存溢出,若还想将内容全读入内存,则必须分多次读入
写操作
f.write(s) #s表示字符串类型
f.writelines(lines) #lines表示:内容为字符串类型的可迭代数据
f.truncate(num) #写入指定num个字节数的数据截取出来写入文件,原数据中的其他数据被情况