Python:IO编程

同步IO与异步IO:
由于CPU和内存的速度远远高于外设的速度,所以,在IO编程中,就存在速度严重不匹配的问题。举个例子来说,比如要把100M的数据写入磁盘,CPU输出100M的数据只需要0.01秒,可是磁盘要接收这100M数据可能需要10秒,怎么办呢?有两种办法:

  • 同步IO:CPU等着,也就是程序暂停执行后续代码,等100M的数据在10秒后写入磁盘,再接着往下执行,这种模式称为同步IO;好比你去麦当劳点餐,你说“来个汉堡”,服务员告诉你,对不起,汉堡要现做,需要等5分钟,于是你站在收银台前面等了5分钟,拿到汉堡再去逛商场,这是同步IO。

  • 异步IO:CPU不等待,只是告诉磁盘,“您老慢慢写,不着急,我接着干别的事去了”,于是,后续代码可以立刻接着执行,这种模式称为异步IO。使用异步IO来编写程序性能会远远高于同步IO,但是异步IO的缺点是编程模型复杂。想想看,你得知道什么时候通知你“汉堡做好了”,而通知你的方法也各不相同。如果是服务员跑过来找到你,这是回调模式,如果服务员发短信通知你,你就得不停地检查手机,这是轮询模式。总之,异步IO的复杂度远远高于同步IO。

这里只讲同步IO,至于异步IO需要学到服务器再说,因为比较复杂。

文件读写

Python内置了读写文件的函数,用法和C是兼容的。具体基本用法如下:

# 读文件第一中写法,并且可以忽略编码错误: errors='ignore'
try:
    f = open('C:/Users/Administrator/Desktop/test.txt', 'r', encoding='gbk', errors='ignore')
    print(f.read())
finally:
    if f:
        f.close()

# 读文件第二种写法,推荐,这种自动 f.close(),其实就是上面的简写
with open('C:/Users/Administrator/Desktop/test.txt', 'r', encoding='gbk') as f:
    # 以下方法会一次性读取全部内容,适合内容少的,如果是内容多的情况可以反复调用read(size)方法,
    # 调用readline()可以每次读取一行内容,调用readlines()一次读取所有内容并按行返回list,这个适合配置文件
    print(f.read())

# 用'rb'模式打开文件是二进制
with open('C:/Users/Administrator/Desktop/test.txt', 'rb') as f:
    print(f.read())

# 写文件,当我们写文件时,操作系统往往不会立刻把数据写入磁盘,而是放到内存缓存起来,空闲的时候再慢慢写入。只有调用close()方法时,
# 操作系统才保证把没有写入的数据全部写入磁盘。忘记调用close()的后果是数据可能只写了一部分到磁盘,剩下的丢失了。
with open('C:/Users/Administrator/Desktop/test.txt', 'w', encoding='gbk') as f:
    f.write('Hello, world!')

# 如果我们希望追加到文件末尾怎么办?可以传入'a'以追加(append)模式写入
with open('C:/Users/Administrator/Desktop/test.txt', 'a', encoding='gbk') as f:
    f.write('我是新添加的')

StringIO和BytesIO

如何在内存中进行读写数据?那么就可以用StringIO和BytesIO:

# StringIo
from io import StringIO

# 写入
f = StringIO()
f.write('明明很帅')
# f.getvalue()可以获取
print(f.getvalue())

# 读取数据
f = StringIO('Hello!\nHi!\nGoodbye!')
while True:
    s = f.readline()
    if s == '':
        break
    print(s.strip())  # 把末尾的'\n'删掉

# BytesIO,用于操作二进制数据
from io import BytesIO

# 写入
f = BytesIO(b'\xe4\xb8\xad\xe6\x96\x87')
# 读取数据
print(f.read())
f.write("啦啦啦".encode('utf-8'))
# 取数据
print(f.getvalue())

系统文件目录的操作

如果要在Python程序中执行这些目录和文件的操作怎么办?其实操作系统提供的命令只是简单地调用了操作系统提供的接口函数,Python内置的os模块也可以直接调用操作系统提供的接口函数。具体用法如下(只是其中一小部分):

import os

# 操作系统类型,如果是posix,说明系统是Linux、Unix或Mac OS X,如果是nt,就是Windows系统。
print(os.name)
# 要获取详细的系统信息,可以调用uname()函数,但是在Windows上不提供,所以调用以下代码会报错
# print(os.uname())
# 获取操作系统全部的环境变量
print(os.environ)
# 要获取某个环境变量的值,可以调用os.environ.get('key')
print(os.environ.get('PATH'))
# 查看当前目录的绝对路径
print(os.path.abspath('.'))
# 在某个目录下创建一个新目录,首先把新目录的完整路径表示出来,千万不要自己去拼凑,很容易出错的
print(os.path.join('F:/Pythonproject/test_dir','dir'))
# 同样的道理,要拆分路径时,也不要直接去拆字符串,而要通过os.path.split()函数,这样可以把一个路径拆分为两部分,后一部分总是最后级别的目录或文件名:
print(os.path.split('F:/Pythonproject/test_dir'))
# 然后创建一个目录:
os.mkdir('F:/Pythonproject/test_dir/dir')
# 删除这个目录
os.rmdir('F:/Pythonproject/test_dir/dir')
# os.path.splitext()可以直接让你得到文件扩展名,很多时候非常方便
print(os.path.splitext('F:/Pythonproject/test_dir/_init_.py'))
# 另外还有对文件重命名: os.rename(),删掉文件:os.remove('test.py')
# 列出当前目录下的所有目录
print([x for x in os.listdir('.') if os.path.isdir(x)])
# 要列出所有的.py文件
print([x for x in os.listdir('.') if os.path.isfile(x) and os.path.splitext(x)[1]=='.py'])

序列化

我们把变量从内存中变成可存储或传输的过程称之为序列化,在Python中叫pickling,反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化,即unpickling。以下代码将演示如何讲一个变量,一个json,一个对象如何序列化和反序列化:

import pickle

# 变量序列化
d = dict(name='Bob', age=20, score=88)
# 将序列化的写入文件
try:
    f = open('C:/Users/Administrator/Desktop/test.txt', 'wb')
    # pickle.dumps()方法把任意对象序列化成一个bytes,然后,就可以把这个bytes写入文件。
    # 或者用另一个方法pickle.dump()直接把对象序列化后写入一个file-like Object
    # dumps = pickle.dumps(d)
    dump = pickle.dump(d, f)
finally:
    f.close()

# 变量反序列化
try:
    f = open('C:/Users/Administrator/Desktop/test.txt', 'rb')
    # 可以先把内容读到一个bytes,然后用pickle.loads()方法反序列化出对象,也可以直接用pickle.load()
    # 方法从一个file-like Object中直接反序列化出对象。
    load = pickle.load(f)
    print(load)
finally:
    f.close()

# 将变量序列化成json
import json

d = dict(name='Bob', age=20, score=88)
# dumps()方法返回一个str,内容就是标准的JSON。类似的,dump()方法可以直接把JSON写入一个file-like Object。
dumps = json.dumps(d)
print(dumps)

# 要把JSON反序列化为Python对象,用loads()或者对应的load()方法,前者把JSON的字符串反序列化,后者从file-like Object中读取字符串并反序列化:
print(json.loads(dumps))


# 将自定义对象进行序列化
class Student:
    def __init__(self, name, age, score):
        self.name = name
        self.age = age
        self.score = score


# 将对象转换成dict的转换函数
def student2dict(std):
    return {
        'name': std.name,
        'age': std.age,
        'score': std.score
    }


s = Student('Bob', 20, 88)
# 可选参数default就是把任意一个对象变成一个可序列为JSON的对象,我们只需要为Student专门写一个转换函数,再把函数传进去即可
print(json.dumps(s, default=student2dict))
# 下次如果遇到一个Teacher类的实例,照样无法序列化为JSON。我们可以偷个懒,把任意class的实例变为dict
# 因为通常class的实例都有一个__dict__属性,它就是一个dict,用来存储实例变量。也有少数例外,比如定义了__slots__的class。
json_dumps = json.dumps(s, default=lambda obj: obj.__dict__)
print(json_dumps)


# 同样的道理,如果我们要把JSON反序列化为一个Student对象实例,loads()方法首先转换出一个dict对象,
# 然后,我们传入的object_hook函数负责把dict转换为Student实例
def dict2student(d):
    return Student(d['name'], d['age'], d['score'])


print(json.loads(json_dumps, object_hook=dict2student))
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容

  • 本系列主要学习Python的基本使用和语法知识,后续可能会围绕着AI学习展开。Python3 (1) Python...
    猿来如痴阅读 1,833评论 0 1
  • IO在计算机中指Input/Output,也就是输入和输出。由于程序和运行时数据是在内存中驻留,由CPU这个超快的...
    蝴蝶兰玫瑰阅读 350评论 0 1
  • 本篇文章将介绍python里面的I/O编程。更多内容请参考:python学习指南 I/O编程 读写文件时最常见的I...
    小七奇奇阅读 587评论 0 2
  • IO编程概念 IO在计算机中指Input/Output,也就是输入和输出。由于程序和运行时数据是在内存中驻留,由C...
    时间之友阅读 720评论 0 0
  • ◆成熟不是人的心变老,是泪在打转还能微笑。 ◆你若流泪,先湿的是我的心。 ◆有些人说不出哪里好,但就是谁都替代不了...
    最美句子阅读 123评论 0 1