五、IO编程

input/output:输入、输出

Stream(流):Input Stream就是数据从外面(磁盘、网络)流进内存,Output Stream就是数据从内存流到外面去。(流:相当于管道)

由于CPU和内存的速度远高于外设的速度,所以,在IO编程中,就存在速度严重不匹配的问题。例如要把100M的数据写入磁盘,CPU输出100M的数据只需要0.01秒,磁盘要接收这100M数据可能需要10秒,所以存在两种模式:

  1. 同步IO:CPU等着,程序暂停执行后续代码,等100M的数据在10秒后写入磁盘,再接着往下执行
  2. 异步IO:CPU不等待,继续执行后续代码,后续再回来接收。(较复杂)

一、文件读写

  • 文件处理流程
  1. open()函数打开文件,得到文件句柄并赋值(不在同一路径下的需加 .py)
  2. 通过句柄对文件进行操作 (文件句柄相当于下文的 f )
  3. 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\n', '22222222222\n', '33333333333']
    • 写操作:直接新建空文档覆盖原来的文档

      1 f = open('测试文件','w',encoding='utf-8')
      2 f.write('1111\n')
      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下的换行为\r\n,Linux为\n。 编码后再加 " newline=‘ ' ”读取文件真正换行符:\r\n)
    1. 转成二进制:字符串 -----》encode(编码)-----》》bytes
    2. 查看二进制: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\r\n\xe4\xbd\xa0\xe5\xa5\xbd\r\n' 
      1 #使用 wb 新建文件或写入内容,需进行编码
      2 f = open('test1.py','wb')
      3 date = f.write('1234\n你好'.encode('utf-8'))
      4 4# date = f.write(bytes('1234\n你好',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\nhi\ngoodbye')    
     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'\xe4\xb8\xad\xe6\x96\x87'

 

三、操作文件和目录

  • 使用os模块可直接调用操作系统提供的接口函数
    1 import os
    2 print(os.name)
    3 
    4 输出:
    5 nt

    如果是posix,说明系统是LinuxUnixMac 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'\x80\x03}q\x00(X\x04\x00\x00\x00nameq\x01X\x04\x00\x00\x00jackq\x02X\x03\x00\x00\x00ageq\x03K\x12u.'
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

     

posted @ 2018-12-12 15:12  F·灬小人物  阅读(319)  评论(0编辑  收藏  举报