python的IO编程

admin 2022年1月6日01:34:01评论49 views字数 8406阅读28分1秒阅读模式

IO编程包含文件读写及其操作、内存读写。

IO 在编程语言中特指输入和输出「即 input 和 output」。在 IO 编程中 stream (流)是一个重要的概念,一个完整的 IO 操作通常含有 input 和 output 两个数据流,我们称之为输入流和输出流。
由于 CPU 和内存的速度远远超过外设的速度,因此 IO 操作通常分为同步和异步两种方式,我们生活中所使用的操作系统通常情况下设计到 IO 操作的均使用的是异步 IO。那么同步 IO 和异步 IO 的区别是什么

  1. 同步 IO:即在遇到外设读取数据时,CPU 停止后续代码的执行,等待 IO 读取完成在接着执行剩余的代码。
  2. 异步 IO:即在遇到外设读取数据时,CPU 继续执行其他的代码,待 IO 读取完成在返回处理相关数据。

同步 IO 和异步 IO 最大的区别在遇到外设长时间读取数据时,CPU 是否等待 IO 的执行结果

0x1文件操作

0x1.1文件的打开

文件的打开语法:

1
f = open(name[, mode[, buffering]])

各字段含义:
name: 所要打开的文件的名称,
mode:打开文件的方式:

1
2
3
4
5
6
7
8
't'  :  文本模式(默认)
'x' : 写模式,新建一个文件,如果该文件已存在则会报错。
‘r’ : 读模式
'w' : 写模式
'a' : 追加模式
'b' : 二进制模式(可添加到其他模式中使用)
'+' : 读写模式(可添加到其他模式中使用)
'U' : 就是支持所有的换行模式,也就说‘\r’ '\n' '\r\n'都可表示换行,会有一个tuple用来存贮这个文件中用到过的换行符。

buffering : 是否要缓冲

1
2
3
4
0 / False :    代表无缓冲
1 / True : 代表有缓冲
大于一的数字: 代表缓冲区大小(单位是字节)
-1 : 默认系统缓冲区大小

上面mode列出的是基本模式,实际应用中的扩展模式有:

1
2
3
4
5
6
7
8
"r"   以读方式打开,只能读文件,如果文件不存在,会发生异常。
"w" 以写方式打开,只能写文件, 如果文件不存在,创建该文件。如果文件已存在,先清空,再打开文件。
"rb" 以二进制读方式打开,只能读文件 , 如果文件不存在,会发生异常
"wb" 以二进制写方式打开,只能写文件, 如果文件不存在,创建该文件;如果文件已存在,先清空,再打开文件
"rt" 以文本读方式打开,只能读文件 , 如果文件不存在,会发生异常
"wt" 以文本写方式打开,只能写文件, 如果文件不存在,创建该文件,如果文件已存在,先清空,再打开文件 。
"rb+" 以二进制读方式打开,可以读、写文件 , 如果文件不存在,会发生异常
"wb+" 以二进制写方式打开,可以读、写文件, 如果文件不存在,创建该文件。如果文件已存在,先清空,再打开文件。

0x1.2字节读取

  1. read
    1
    2
    f.read(num)           //读出num个字节
    f.read() //读出全部字节
  2. write
    1
    f.write(string)         //将string写入文件

0x1.3行读写

1
2
3
4
F.readline([size])    #读一行,如果定义了size,size的单位是byte,有可能返回的只是一行的一部分
F.readlines([size]) #把文件每一行作为一个list的一个成员,并返回这个list。其实它的内部是通过循环调用readline()来实现的。如果提供size参数,size是表示读取内容的总长,也就是说可能只读到文件的一部分。
F.write(str) #把str写到文件中,write()并不会在str后加上一个换行符
F.writelines(seq) #把seq的内容全部写到文件中。这个函数也只是忠实地写入,不会在每行后面加上任何东西。

0x1.4关闭文件

1
2
3
4
5
fd.close()

#可以在打开文件时使用with关键字,它会帮我们自动的关闭文件:
with open(path, 'r') as f:
// do something

0x1.5codecs

其实Python对多国语言的处理是支持的很好的,它可以处理当下任意编码的字符。

有一点需要清楚的是,当python要做编码转换的时候,会借助于内部的编码,转换过程是这样的:

原有编码 -> 内部编码 -> 目的编码

而codecs提供的方法可以指定一个编码打开文件,使用这个方法打开的文件读取返回的将是unicode。写入时,如果参数是unicode,则使用open()时指定的编码进行编码后写入;如果是str,则先根据源代码文件声明的字符编码,解码成unicode后再进行前述 操作
相对内置的open()来说,这个方法不容易在编码上出现问题。所以,推荐大家在文件读写的时候使用codecs

python的内部是使用unicode来处理的,但是unicode的使用需要考虑的是它的编码格式有两种,一是UCS-2,它一共有65536个码位,另一种是UCS-4,它有2147483648g个码位。

判断安装的python是用什么编码方式:

1
2
import sys
print(sys.maxunicode)

如果输出的值为65535,那么就是UCS-2,如果输出是1114111就是UCS-4编码。

转换成内部码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
c = "风卷残云"
print(type(c))
c = bytes(c,encoding='utf-8')
print(type(c))
print(c)
b = codecs.decode(c, "utf-8") #与c.decode()等效
print(type(b))
print(b)
print(c.decode())

输出:

<class 'str'>
<class 'bytes'>
b'\xe9\xa3\x8e\xe5\x8d\xb7\xe6\xae\x8b\xe4\xba\x91'
<class 'str'>
风卷残云
风卷残云

在python3.x中可以直接将bytes类型的数据转换成其他编码格式,而不用手动先转成unicode。

1
2
3
4
5
6
7
8
9
10
import codecs
a = "你好世界"
# 创建utf-8编码器
look = codecs.lookup('utf-8')
type(a)
a = bytes(a,encoding='utf-8')
b = look.decode(a)
print(b)
输出:
('你好世界', 12)

返回的元组中b[0]是数据,b[1]是长度
用codecs提供的open方法来指定打开的文件的语言编码,它会在读取的时候自动转换为内部unicode

1
f = codecs.open(filepath, 'r', 'utf8')

0x2 目录文件操作

x02.1os 模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
os.sep 可以取代操作系统特定的路径分隔符。windows下为 '\\'
os.name 字符串指示你正在使用的平台。比如对于Windows,它是'nt',而对于Linux/Unix用户,它是 'posix'
os.getcwd() 函数得到当前工作目录,即当前Python脚本工作的目录路径
os.getenv() 获取一个环境变量,如果没有返回none
os.putenv(key, value) 设置一个环境变量值
os.listdir(path) 返回指定目录下的所有文件和目录名
os.remove(path) 函数用来删除一个文件
os.system(command) 函数用来运行shell命令
os.linesep 字符串给出当前平台使用的行终止符。例如,Windows使用 '\r\n',Linux使用 '\n' 而Mac使用 '\r'
os.path.split(path) 函数返回一个路径的目录名和文件名
os.path.isfile() 和os.path.isdir()函数分别检验给出的路径是一个文件还是目录
os.path.exists() 函数用来检验给出的路径是否真地存在
os.curdir 返回当前目录 ('.')
os.mkdir(path) 创建一个目录
os.makedirs(path) 递归的创建目录
os.chdir(dirname) 改变工作目录到dirname
os.path.getsize(name) 获得文件大小,如果name是目录返回0L
os.path.abspath(name) 获得绝对路径
os.path.normpath(path) 规范path字符串形式
os.path.splitext() 分离文件名与扩展名
os.path.join(path,name) 连接目录与文件名或目录
os.path.basename(path) 返回文件名
os.path.dirname(path) 返回文件路径
os.walk(top,topdown=True,onerror=None) 遍历迭代目录
os.rename(src, dst) 重命名file或者directory src到dst 如果dst是一个存在的directory, 将抛出OSError. 在Unix, 如果dst在存且是一个file, 如果用户有权限的话,它将被安静的替换. 操作将会失败在某些Unix 中如果src和dst在不同的文件系统中. 如果成功, 这命名操作将会是一个原子操作 (这是POSIX 需要). 在 Windows上, 如果dst已经存在, 将抛出OSError,即使它是一个文件. 在unix,Windows中有效。
os.renames(old, new) 递归重命名文件夹或者文件。像rename()

0x2.2shutil模块

1
2
3
4
5
6
7
8
9
10
shutil.copyfile( src, dst) 从源src复制到dst中去。当然前提是目标地址是具备可写权限。抛出的异常信息为IOException. 如果当前的dst已存在的话就会被覆盖掉
shutil.move( src, dst) 移动文件或重命名
shutil.copymode( src, dst) 只是会复制其权限其他的东西是不会被复制的
shutil.copystat( src, dst) 复制权限、最后访问时间、最后修改时间
shutil.copy( src, dst) 复制一个文件到一个文件或一个目录
shutil.copy2( src, dst) 在copy上的基础上再复制文件最后访问时间与修改时间也复制过来了,类似于cp –p的东西
shutil.copy2( src, dst) 如果两个位置的文件系统是一样的话相当于是rename操作,只是改名;如果是不在相同的文件系统的话就是做move操作
shutil.copytree( olddir, newdir, True/Flase)
把olddir拷贝一份newdir,如果第3个参数是True,则复制目录时将保持文件夹下的符号连接,如果第3个参数是False,则将在复制的目录下生成物理副本来替代符号连接
shutil.rmtree( src ) 递归删除一个目录以及目录内的所有内容

0x2.3glob

例如当我们想要列出当前目录中所有扩展名为.jpg或.gif的文件的时候

1
2
3
import glob
filelist = glob.glob('*.jpg') + glob.glob('*.gif')
print(filelist)

0x3序列化

我们把变量从内存中变成可存储或传输的过程称之为序列化。
序列化之后,就可以把序列化后的内容写入磁盘,或者通过网络传输到别的机器上。
反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化。

python的序列化可用pickle和json模块

  • json:用于(不同平台和多语言)字符串和python数据类型进行转换
  • pickle:用于python特有的类型和python的数据类型间进行转换(所有python数据类型)

0x3.1pickle

Python提供两个模块来实现序列化:cPickle和pickle。这两个模块功能是一样的,区别在于cPickle是C语言写的,速度快,pickle是纯Python写的,速度慢。
python3中已经没有cPickle模块
pickle模块的作用:

  1. 可以将对象转换为一种可以传输或存储的格式。
  2. pickle模块将任意一个python对象换成一个系统字节的操作过程叫做串行化对象。
  3. pickle模块实现了python的所有数据序列化和反序列化。它不是用于多种语言间的传输,它仅作为python对象的持久化或者python程序间进行互相传输对象的。

dump和dumps的区别:

  • dump是将对象序列化并保存到文件中
  • dumps是将对象序列化

load和loads的区别:

  • load将序列化字符串从文件读取并反序列化
  • loads将序列化字符串反序列化

范例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import pickle
data1=[1,'a',2,'b',3,'c']
pi=pickle.dumps(data1) #序列化对象
print(pi)
print(pickle.loads(pi)) #反序列胡对象


f=open('output.txt','wb')
data2=['py','th','on','123']
pickle.dump(data2,f) #序列化对象到文件
f=open('output.txt','rb')
read=pickle.load(f)#文件中发序列化对象
print(read)


output:

b'\x80\x03]q\x00(K\x01X\x01\x00\x00\x00aq\x01K\x02X\x01\x00\x00\x00bq\x02K\x03X\x01\x00\x00\x00cq\x03e.'
[1, 'a', 2, 'b', 3, 'c']
['py', 'th', 'on', '123']
[Finished in 0.2s]

0x3.2json

json.dumps()是将字典类型转化成字符串类型。
json.loads()将字符串类型转化成字典类型
json.dump()用于将dict类型的数据转成str,并写入到json文件中
json.load()用于从json文件中读取数据。
范例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import json
data1={'a':1,'b':2,'c':3}
dus=json.dumps(data1)#将字典类型转化成字符串类型
print(dus,type(dus))
los=json.loads(dus)
print(los,type(los))#将字符串类型转化成字典类型

data2={'a':'4','b':'5','c':'6'}
with open('input.txt','w') as f: #用于将dict类型的数据转成str,并写入到json文件中
json.dump(data2,f)
with open("input.txt",'r') as f1:#用于从json文件中读取数据。
print(json.load(f1))


output:
{"a": 1, "b": 2, "c": 3} <class 'str'>
{'a': 1, 'b': 2, 'c': 3} <class 'dict'>
{'a': '4', 'b': '5', 'c': '6'}

0x3.3shelve

shelve是通过key,value将内存中的数据通过文件存储的方式实现持久化,可以支持任何pickle所支持的任何Python数据格式:

1
2
3
4
5
6
7
8
9
import shelve
d = shelve.open("shelve_test")

name = "python"
info = {"age":21,"sex":"man"}

d["name"] = name
d["info"] = info
d.close()

此时就已经完成了将内存数据持久化的一个过程,执行完毕之后,在当前目录下回生成一个名为“shelve_test.db”的文件。那么,我们又该如何将数据取出来呢,请看接下来的操作

1
2
3
4
5
import shelve
d = shelve.open("shelve_test")
name = d["name"]
info = d["info"]
d.close()

此时就将数据从磁盘中从新取出来,放置在内存中,我们就可以对它进行操作了。

0x4内存读写

python 通过 StringIO 和 BytesIO 来读写内存中的数据。

0x4.1StringIO

StringIO 顾名思义就是读写内存中的字符串。
StringIO的行为与file对象非常像,但它不是磁盘上文件,而是一个内存里的“文件”,我们可以像操作磁盘文件那样来操作StringIO
简单实例:

1
2
3
4
5
6
7
#!/usr/bin/env python3
#-*- coding:utf-8 -*-
import io

f = io.StringIO()
f.write("hello world!")
print(f.getvalue())

f=StringIO.StringIO([buf])
此实例类似于open方法,不同的是它并不会在硬盘中生成文件,而只寄存在缓冲区;可选参数buf是一个str或unicode类型。它将会与其他后续写入的数据存放在一起(注意,若要在初始化数据之后继续写入数据,则在写入数据之前,应先将读写位置移动到结尾,然后再写入,否则,初始化数据会被覆盖掉,因为读写位置默认是0)。

StringIO类中的方法:

方法 描述
f.read([n]) 参数n限定读取长度,int类型;缺省状态为从当前读写位置读取对象s中存储的所有数据。读取结束后,读写位置被移动。
f.readline([length]) 参数length限定读取的结束位置,int类型,缺省状态为None:从当前读写位置读取至下一个以“\n”为结束符的当前行。读写位置被移动。
f.readlines([sizehint]) 参数sizehint为int类型,缺省状态为读取所有行并作为列表返回,除此之外从当前读写位置读取至下一个以“\n”为结束符的当前行。读写位置被移动。
f.write(s) 从读写位置将参数s写入给对象s。参数s为str或unicode类型。读写位置被移动。
f.writelines(list) 读写位置将list写入给对象s。参数list为一个列表,列表的成员为str或unicode类型。读写位置被移动。
f.getvalue() 此函数没有参数,无论读写位置在哪里,都能够返回对象s中的所有数据。
f.truncate([size]) 1》有size参数,无论读写位置在哪里,都从起始位置开始,裁剪size字节的数据。2》不带size参数,将当前读写位置之前的数据,裁剪下来。
f.tell() 返回当前读写位置。
f.seek(pos[,mode]) 移动当前读写位置至pos处,可选参数mode为0时将读写位置移动至pos处,为1时将读写位置从当前位置起向前或向后移动pos个长度,为2时将读写位置置于末尾处再向前或向后移动pos个长度;mode的默认值为0。
f.close() 释放缓冲区,执行此函数后,数据将被释放,也不可再进行操作。
f.isatty() 此函数总是返回0。
f.flush() 刷新内部缓冲区。

0x4.2BytesIO

BytesIO 用来读写内存中的二进制数据。
例子:

1
2
3
4
5
6
7
#!/usr/bin/env python3
#-*- coding:utf-8 -*-
import io

f = io.BytesIO()
f.write('keinYe'.encode('utf-8'))
print(f.getvalue())

参考文章:
python文件操作(一)基础文件操作:http://www.361way.com/python-file-basics/4627.html
Python IO 编程 http://keinye.com/2019/02/python-base-io/
Python StringIO实现内存缓冲区中读写数据https://www.cnblogs.com/misswangxing/p/7921665.html
Python 中文件 I/O 高效操作处理的技巧https://juejin.im/entry/58ec780f8d6d810058056396
廖雪峰的官方网站 https://www.liaoxuefeng.com/wiki/897692888725344/92303055545616
python中转换模块codecs的讲解 http://www.php.cn/python-tutorials-412484.html
python–序列化(dump和dumps的区别、load和loads的区别、json与pickle模块的区别) https://blog.csdn.net/qq_44525050/article/details/87947301

FROM :blog.cfyqy.com | Author:cfyqy

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年1月6日01:34:01
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   python的IO编程http://cn-sec.com/archives/721862.html

发表评论

匿名网友 填写信息