input/output:输入、输出
Stream(流):Input Stream就是数据从外面(磁盘、网络)流进内存,Output Stream就是数据从内存流到外面去。(流:相当于管道)
由于CPU和内存的速度远高于外设的速度,所以,在IO编程中,就存在速度严重不匹配的问题。例如要把100M的数据写入磁盘,CPU输出100M的数据只需要0.01秒,磁盘要接收这100M数据可能需要10秒,所以存在两种模式:
- 同步IO:CPU等着,程序暂停执行后续代码,等100M的数据在10秒后写入磁盘,再接着往下执行
- 异步IO:CPU不等待,继续执行后续代码,后续再回来接收。(较复杂)
一、文件读写
- 文件处理流程
- open()函数打开文件,得到文件句柄并赋值(不在同一路径下的需加 .py)
- 通过句柄对文件进行操作 (文件句柄相当于下文的 f )
- close()函数关闭文件
- 文件打开模式
- 读操作:解码默认GBK; open() 函数还可接收 errors 参数,可用 errors=ignore 忽略编码错误。
1 r:只读,w:只写 ,a:追加 2 f = open('文件名','权限',encoding='utf-8') #传入需要打开的文件名并进行解码 3 data = f.read() #查看文件 4 print(date) 5 f.close() #关闭文件
1 f = open('测试文件','r',encoding='utf-8') 2 # date = f.read() 3 # print(date) #文件只打印一次,后面再打印不显示内容 4 # print(f.readable()) #判断权限 5 # print(f.readline()) #打印一行,没内容即不打印 6 print(f.readlines()) #将文件内容每段以字符串的方式显示出来,并存在一个列表中 7 f.close() 8 9 输出: 10 ['11111111111 ', '22222222222 ', '33333333333']
-
写操作:直接新建空文档覆盖原来的文档
1 f = open('测试文件','w',encoding='utf-8') 2 f.write('1111 ') 3 f.writelines(['111','222']) #以列表的方式写入,内容只能是字符串 4 f.writable() 5 f.close()
- 追加操作:将内容写到文件最后,不覆盖文件内容
- r+:可读可写;w+;a+;x+。
1 f = open('测试文件','r+',encoding='utf-8') 2 f.write('内容') #将内容覆盖到测试文件的开头,根据占用的字节进行替换
- with...as...:可不用 close() 关闭文件
1 #可使用with..as..:来打开或修改文件,不需要用close关闭。 2 with open('测试文件','r',encoding='utf-8') as arc_f,/ #字符太长使用‘/‘进行换行处理 3 open('新文件','w',encoding='utf-8') as dst_f:
- 修改文件上的内容
1 #查看文件内容并赋值到date上 2 src_f = open('测试文件','r',encoding='utf-8') 3 date = src_f.readline() 4 src_f.close() 5 #修改date索引位置的内容 6 dst_f = open('测试文件','w',encoding='utf-8') 7 dst_f.writelines(date[0]) 8 dst_f.close()
- rb、wb、ab:可用于读取二进制文件,比如图片、视频等,不能指定编码(Windows下的换行为 ,Linux为 。 编码后再加 " newline=‘ ' ”读取文件真正换行符: )
- 读操作:解码默认GBK; open() 函数还可接收 errors 参数,可用 errors=ignore 忽略编码错误。
- 转成二进制:字符串 -----》encode(编码)-----》》bytes
- 查看二进制:bytes -----》decode(解码)-----》》字符串
1 #使用 rb 进行查看,返回二进制数 2 f = open('test1.py','rb') 3 date = f.read() 4 print(date) 5 f.close() 6 7 输出: 8 b'11111 xe4xbdxa0xe5xa5xbd '
1 #使用 wb 新建文件或写入内容,需进行编码 2 f = open('test1.py','wb') 3 date = f.write('1234 你好'.encode('utf-8')) 4 4# date = f.write(bytes('1234 你好',encoding='utf-8')) 5 f.close()
- flush():刷新文件
- seek():里面加数字,表示文件光标移动多少个字节(一个汉字占用三个字节,排除第一个汉字时为:文件句柄.seek(3),默认为: 文件句柄.seek(3,0) )
- 文件句柄.seek(3,1)表示相对位置,即从上一个移到的位置接着往下移动;文件句柄.seek(-3,2)表示光标从后往前的位置。
- read():文件句柄.read(1)表示读取文件一个位置的内容,汉字占用三个字节也用一个表示。与其它方法的表示不一样
- truntruncate():加数字表示截取文件多少个字节的内容。需以写的方式打开,w与w+除外。
1 #使用seek倒查文件最后一行 2 f = open('test.txt', 'rb') 3 for i in f: # 使用for i in f 系统不会把所有数据读到内存中,而是需要读取时再读 4 offs = -10 # 定义一个偏移量,因为倒查,所以为负数 5 while True: 6 f.seek(offs, 2) # 7 data = f.readlines() # 使用readlines(),会得到一个光标所在位置到结尾所有行的一个列表 8 if len(data) > 1: # 当列表大于1时,说明已取到完整的最后一行 9 print(data[-1].decode('utf-8')) 10 break 11 offs *= 2 # 如果得到的列表不大于1,说明最后一行得到了一部分,就把偏移量*2,再进行循环
二、StringIO和BytesIO
- StringIO:在内存中读、写str,可先用一个str 初始化内容
1 #读取StringIO内的文件 2 from io import StringIO 3 f = StringIO('hello hi goodbye') 4 while True: 5 s = f.readline() 6 if s == '': 7 break 8 print(s.strip()) 9 10 输出: 11 hello 12 hi 13 goodbye
1 #将字符串写入StringIO 2 from io import StringIO 3 f = StringIO() 4 date = f.write('hello') 5 f.write(' ') 6 f.write('world!') 7 print(date) 8 print(f.getvalue()) #getvalue 获取写入后的字符串 9 10 输出: 11 5 12 hello world!
- BytesIO:在内存中读、写二进制数据
1 #将bytes写入BytesIO 2 from io import BytesIO 3 f = BytesIO() 4 date = f.write('中文'.encode('utf-8')) #需将str经过utf-8编码为bytes 5 print(date) 6 print(f.getvalue()) 7 8 输出: 9 6 10 b'xe4xb8xadxe6x96x87'
三、操作文件和目录
- 使用os模块可直接调用操作系统提供的接口函数
1 import os 2 print(os.name) 3 4 输出: 5 nt
如果是
posix
,说明系统是Linux
、Unix
或Mac OS X
,如果是nt
,就是Windows
系统; uname() 函数可查看详细系统信息,Windows上不提供该函数; - 环境变量:保存在os.environ变量中,获取某个变量的值可用 os.environ,get('key’) 进行调用;
- 文件操作:使用 os.path.join() 函数将两个路径合并,可处理不同操作系统的分割符( Windows: ;Linux:/ )
1 import os 2 d = os.path.abspath('.') #查看当前目录的绝对路径 3 #os.path.join('/Users/michael', 'testdir') #在Linux下创建; 4 os.path.join('C:\Users\F·iy\Desktop','testdir') #创建新目录,先表示出新目录的完整路径; 5 os.mkdir('C:\Users\F·iy\Desktop\testdir') #创建目录 6 os.rmdir('C:\Users\F·iy\Desktop\testdir') #删除目录
使用 os.path.split() 函数对路劲拆分为两部分,后部分为最后的文件目录或文件名; os.path.splitext() 函数可得到文件扩展名; os.rename() 对文件重命名
1 os.path.split('C:\Users\F·iy\Desktop\testdir') 2 os.path.splitext('test.py') #得到('test', '.py') 3 os.rename('test.txt','test.py') #将.txt改为.py文件 4 os.remove('test.py') #删掉文件
1 #列出当前目录下的所有文件 2 a = [x for x in os.listdir('.') if os.path.isdir(x)] 3 #列出所有的.py文件 4 b = [x for x in os.listdir('.') if os.path.splitext(x)[1]=='.py'] 5 print(a,b) 6 7 输出: 8 ['__pycache__'] ['func.py', 'test.py', '__init__.py']
四、序列化
把变量从内存中变成可存储或传输的过程;(特定的序列化称为pickling)
序列化之后,就可以把序列化后的内容写入磁盘,或者通过网络传输到别的机器上。
反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化,即unpickling。
1 #使用pickle.dump()与pickle.load() 2 3 import pickle 4 d = dict(name='jack',age=18) 5 #直接把对象序列化后写入一个file-like Object(one.txt)里; 6 f = open('one.txt','wb') 7 pickle.dump(d,f) 8 f.close() 9 #从一个file-like Object里直接反序列化出对象 10 f = open('one.txt','rb') 11 d = pickle.load(f) 12 print(d) 13 14 输出: 15 {'name': 'jack', 'age': 18}
1 #使用pickle.dumps() 与pickle.loads() 2 3 import pickle 4 d = dict(name='jack',age=18) 5 a = pickle.dumps(d) #把任意对象序列化成一个bytes 6 b = pickle.loads(a) #反序列化出对象 7 print(a) 8 print(b) 9 10 输出: 11 b'x80x03}qx00(Xx04x00x00x00nameqx01Xx04x00x00x00jackqx02Xx03x00x00x00ageqx03Kx12u.' 12 {'name': 'jack', 'age': 18}
- JSON:序列化的标准格式 json模块 更通用、更符合web标准。
1 #使用json.dumps()与json.loads() 2 3 import json 4 d = dict(name='Bob', age=20, score=88) 5 a = json.dumps(d) #直接返回一个str 6 b = json.loads(a) #反序列化 7 print(a) 8 print(b) 9 10 输出: 11 {"name": "Bob", "age": 20, "score": 88} 12 {'name': 'Bob', 'age': 20, 'score': 88}
1 import json 2 d = dict(name='Bob', age=20) 3 #创建文件 4 f = open('text.txt','w') 5 json.dump(d,f) 6 #反序列化 7 f = open('text.txt','r') 8 b = json.load(f) 9 print(b) 10 11 输出: 12 {'name': 'Bob', 'age': 20
- 序列化 class 类,先将其转化为 dict 形式,使用 default 转换为可序列对象;反序列化时用 loads() 转换出一个
dict
对象后,使用 object_hook负责把 dict 转换为 Student 实例1 import json 2 3 class Student(object): 4 def __init__(self, name, age, score): 5 self.name = name 6 self.age = age 7 self.score = score 8 9 def get(self): 10 return '%s age is %s ,score:%s'% (self.name,self.age,self.score) 11 #为class写一个转换函数 12 def student_dict(std): 13 return { 14 'name': std.name, 15 'age': std.age, 16 'score': std.score 17 } 18 19 s = Student('jack', 18, 90) 20 a = json.dumps(s, default=student_dict) #可选参数default可把任意一个对象变成一个可序列为JSON的对象 21 #将class的实例变为dict,通常class的实例都有一个__dict__属性 22 # print(json.dumps(s, default=lambda obj: obj.__dict__)) 23 print(a) 24 25 #反序列化为class类的对象实例,先转换为dict后再转为实例 26 def dict_student(d): 27 return Student(d['name'], d['age'], d['score']) 28 b = json.loads(a,object_hook=dict_student) 29 print(b) #实例对象 30 print(b.get()) 31 32 输出: 33 {"name": "jack", "age": 18, "score": 90} 34 <__main__.Student object at 0x000000B529F2C908> 35 jack age is 18 ,score:90