Python -- I/O编程

Posted bravesunforever

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python -- I/O编程相关的知识,希望对你有一定的参考价值。

I/O编程

Input/Output  输入/输出

Stream(流)是一个很重要的概念,可以把流想象成一个水管,数据就是水管里的水

Input Stream就是数据从外面(磁盘、网络)流进内存,Output Stream就是数据从内存流到外面去

    由于CPU和内存的速度远远高于外设的速度,所以,在I/O编程中,存在速度严重不匹配的问题。例子:比如要把100M的数据写入磁盘(这是output),CPU输出100M只需要0.01s,可是磁盘要接收这100M数据可能需要10s,怎么办呢?有两种解决方法:

第一种:CPU等着,这种模式称为同步IO

第二种:CPU不等着,这种模式称为异步IO

同步和异步的区别:在于是否等待IO执行的结果.

例子:好比你去麦当劳点餐,你说“来个汉堡”,服务员告诉你,对不起,汉堡要现做,需要等待5分钟, 有两种处理方式:

(1)你站在收银台前等了5分钟,拿到汉堡再去逛商场,这是同步IO

(2)你先逛商场,等做好了,服务员再通知你,这样你可以立刻去干别的事情(逛商场),这是异步IO

     结论:很明显,使用异步IO来编写程序性能会远远高于同步IO,但是异步IO的缺点是编程模型复杂。而服务员如何通知你汉堡做好了,方法各不相同。

   (1) 如果是服务员跑过来找你,这是回调模式

   (2)如果服务员发短信通知你,你就要不停地检查手机,这是轮询模式

    总之,异步IO的复杂度远远高于同步IO

   操作IO的能力都是由操作系统提供的,每一种编程语言都会把操作系统提供的低级C接口封装起来方便使用,Python也不例外

 

文件读写

读文件(read)和写文件(write)

注意:由于“ \\ ”是字符串中的转义符,所以表示路径时,使用“ \\\\ ”或者 “ / ”或者“ \\\\ ”

 

Python对文本文件和二进制文件采用统一的操作步骤,即“ 打开 - 操作 - 关闭”

读写文件的模式说明:

访问模式 说明
r 默认模式,以只读方式打开文件,文件的指针将会放在文件的开头。如果文件不存在,返回异常FileNotFoundError
w 打开一个文件只用于写入。如果文件已存在,则将其覆盖。如果文件不存在,创建新文件
a 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也即是,新的内容会被追加到已有内容之后。如果文件不存在,创建新文件进行写入。
x 创建写模式,文件不存在则创建,存在则返回异常FileExistsError
t 文本文件模式,默认值
rb 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。
wb 以二进制格式打开,……(其余的与相应模式的用法相同)
ab 以二进制格式打开,……(其余的与相应模式的用法相同)
+ 与r/w/x/a/rb/wb/ab一同使用,在原功能基础上,使其同时具有读写功能
b 二进制文件模式

注意:(追加append)

 

open( )函数:打开一个文件对象

    格式:open( 文件名,文件模式)

文件模式:“r”模式表示读取utf-8编码的文本文件; “rb”模式表示读取二进制文件

文件模式:“w”模式表示写文本文件;“wb”模式表示写二进制文件

字符编码:

读取非utf-8编码的文本文件,使用encoding参数

文本文件夹杂一些非法编码的字符时,遇到这种情况,open()函数使用errors参数,表示如果遇到编码错误后如何处理,最简单的方式是直接忽略。

f = open(/Users/michael/notfound.txt, rb,encoding=gbk,errors=ignore)

 

读文件——文件存在

 如果文件成功打开,读取文件的方式:

read( )方法:一次读取文件的全部内容,Python把内容读到内存,用一个str对象表示;如果文件有10G,内存就爆了,所以保险起见,可以反复调用read(size)方法。

read(size)方法:每次最多读取size个字节的内容。

readline( ):每次读取一行内容

readlines( ):一次读取所有内容并按行返回一个列表list,列表中的每一个元素为文件中的每一行数据。同时,每一个元素结尾都带一个 \\n标志。

  readlines(h):参数可选,如果给出,读入h行

 

close( )方法

    文件使用完毕后必须关闭,有两方面原因:

(1)文件对象会占用操作系统的资源。  (2)操作系统同一时间能打开的文件数量也是有限的。

 

为了保证无论是否出错都能正确地关闭文件,有两种实现方式:

(1)使用try ... finally来实现,因为finally语句块一定会被执行。

(2)with语句:是因为with语句能自动调用close( )方法

 

使用try ... finally来实现:

1 try:
2     f = open(/path/to/file, r)
3     print(f.read())
4 finally:
5     if f:
6         f.close()

 with语句:

1 with open(/path/to/file, r) as f:
2     print(f.read())

这和前面的try ... finally是一样的,但是代码更佳简洁,并且不必调用f.close()方法。

 

读文件——文件不存在

 如果文件不存在,ope( )函数会抛出一个IOError错误,并且给出错误码和详细的信息告诉你文件不存在:

1 f = open(/Users/michael/notfound.txt, r)

运行结果:

技术图片

 写文件

   当我们写文件时,操作系统往往不会立刻把数据写入磁盘,而是放到内存缓存起来,空闲的时候再慢慢写入。

只有调用close( )方法时,操作系统才保证把没有写入的数据全部写入磁盘。

忘记调用close( )的后果是数据可能只写了一部分到磁盘,剩下的丢失了。所以,还是用with语句来得保险:

with open(/Users/michael/test.txt, w) as f:
    f.write(Hello, world!)

 

文件的定位读写

  背景:在实际开发中,可能会需要从文件的某个特定位置开始读写。此时,需要对文件的读写位置进行定位。

两种定位方式:

(1)获取文件当前的读写位置:tell( )方法

(2)定位到文件的指定读写位置:seek (offset, whence )方法 

 

1、使用tell方法来获取文件当前的读写位置

tell方法返回文件的当前位置,即文件指针当前位置

f=open("theima.txt","r")
str=f.read(4)
print("读取的数据是:",str)

#查找当前位置
position=f.tell()
print("当前文件位置:",position)

 

2、使用seek方法定位到文件的指定读写位置

格式: seek( offset [ , whence ] )

offset:偏移量,即需要移动的字节数

whence表示方向,有三个值:

(1)SEEK_SET或者0:默认值,表示从文件的起始位置开始偏移

(2)SEEK_CUR或者1:表示从文件的当前位置开始偏移

(3)SEEK_END或者2:表示从文件末尾开始偏移

 

 

文件的重命名和删除

   Python的os模块默认已包含了这些功能

文件的重命名

os模块的rename方法:  os.rename( src, dst ) 

     src:需要修改的文件名, dst :修改后的新文件名

 

文件的删除

os模块的remove方法: os.remove( path )

path:指定路径下的文件

import os

os.rename("毕业论文.txt","毕业论文-最终版.txt")

os.remove("毕业论文.txt")

 

文件夹的相关操作

创建文件夹

   os模块的mkdir方法

import os
os.mkdir("张三")

 

获取当前目录

   os模块的getcwd方法

import os
os.getcwd()

 

改变默认目录

os模块的chdir方法

例如,将当前目录改编为上一级目录

import os
os.chdir("../")

 

获取目录列表

os模块的listdir方法

例如,获取当前路径下的子目录列表

import os
os.listdir("./")

 

删除文件夹

os模块的rmdir方法

例如,删除当前路径下的“张三”目录

import os
os.rmdir("张三")

 

 

StringIO和BytesIO

   StringIO和BytesIO是在内存中操作str 和bytes(注意:加了s)的方法,使得和读写文件具有一致的接口。

   getvalue( )方法用于获得写入write后的值

 StringIO

数据读写不一定是文件,也可以在内存中读写。

StringIO就是在内存中读写str

要把str写入StringIO,我们需要先创建一个StringIO,然后,像文件一样写入即可:

1 from io import StringIO
2 
3 f=StringIO()
4 f.write(Hello)
5 f.write( , )
6 f.write(World)
7 print(f.getvalue())

 技术图片

 

要读取StringIO,可以用一个str初始化StringIO,然后,像读文件一样读取:

1 # read from StringIO:
2 from io import StringIO
3 f = StringIO(水面细风生,\\n菱歌慢慢声。\\n客亭临小市,\\n灯火夜妆明。)
4 while  True:
5     s=f.readline()
6     if s=="":
7         break
8     print(start to print:)
9     print(s.strip())

运行结果: 可以看出是一行一行打印出来的

技术图片

 

BytesIO

StringIO操作的只能是str,如果要操作二进制数据,就需要使用BytesIO。

 BytesIO实现了在内存中读写bytes,我们创建一个BytesIO,然后写入一些bytes:

 注意:1、utf-8编码,使用的是encode参数,中间是英文句号点(.)

            2、写入的不是str,而是经过UTF-8编码的bytes。

1 from io import BytesIO
2 
3 f=BytesIO()
4 f.write(中文.encode(utf-8))
5 print(f.getvalue())

技术图片

 

和StringIO类似,可以用一个bytes初始化BytesIO,然后,像读文件一样读取:

1 from io import BytesIO
2 f=BytesIO(b\\xe4\\xb8\\xad\\xe6\\x96\\x87)
3 print(f.read())

技术图片

 

以上是关于Python -- I/O编程的主要内容,如果未能解决你的问题,请参考以下文章

Python -- I/O编程

Python基础10—I/O编程

Python 15 I/O编程

用于 Python 中竞争性编程的快速 I/O

Python学习:并发编程之IO模型

python并发编程:异步IO(Asynchronous I/O)