本篇文章将介绍python里面的I/O编程。更多内容请参考:python学习指南

I/O编程

读写文件时最常见的IO操作。Python内置了读写文件的函数,用法和C是兼容的。

读写文件前,我们必须了解一下,在磁盘上读写文件的功能都是由操作系统提供的,现代操作系统不允许普通的程序直接操作磁盘,所以,读写文件就是请求操作系统打开一个文件对象(通常称为文件描述符),然后,通过操作系统提供的接口从这个文件对象中读取数据(读文件),或者把数据写入这个文件对象(写文件)。

在I/O编程中,Stream(流)是一种重要的概念,分为输入流(Input Stream)和输入流(Output Stream)。我们可以把流理解为一个水管,一个负责输入,一个负责输出,这样读写就可以实现同步。

文件读写

打开文件

读写文件是最常见的IO操作。Python内置了读写文件的函数,方便了文件的IO操作。

文件读写之前需要打开文件,确定文件的读写模式。open函数用来打开文件,语法如下:

open(name[, mode[, buffering]])

open函数使用一个文件作为唯一的强制参数,然后返回一个文件对象。模式(mode)和缓冲区(buffering)参数都是可选的,默认模式是读模式,默认缓冲区是无。

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

>>>f = open("user/michael/notfound.txt", "r")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
FileNotFoundError: [Errno 2] No such file or directory: 'user/michael/notfound.txt'

文件模式

open函数打开中的mode参数,通过改变mode参数可以实现对文件的不同操作

功能描述
'r' 读模式
'w' 写模式
'a' 追加模式
'b' 二进制模式(可添加到其它模式中使用)
'+' 读/写模式(可添加到其它模式中使用)

一般处理文本文件时,是用不到'b'参数的,但如果处理其它类型的文件(二进制文件),比如mp3或者图形,就应该在模式中加上'b',这在爬虫中处理媒体文件很常用。

文件缓冲区

open函数中第三个可选参数buffering控制着文件的缓冲。如果参数是0,I/O操作就是无缓冲的,直接将数据写到硬盘上;如果参数是1,I/O操作就是有缓冲的,数据先写入到内存里,只有使用flush函数或者close函数才会将数据更新到硬盘;如果参数大于1的数据则代表着缓冲区的大小(单位是字节),-1(或者任何负数)代表使用默认缓冲区的大小。

文件读取

文件读取主要分为按字节读取和按行读取,经常用到的方法有read()readline()readlines()close()

>>>f = open(r"c:\\text\\xiaoqi.txt", "r")
>>>f.read() #调用read()方法可以一次性地将文件内容全部读到内存中
'xiaoqi'
f.close() #文件读取完成后必须关闭

由于文件操作可能会出现IO异常,一旦出现IO异常,后面的close()

方法就不会调用。所以为了保证程序的健壮性,我们需要使用try...finally来实现。

try
f = open(r'c:\\text\\xiaoqi.txt')
print(f.read())
finally:
if f:
f.close()

Python提供了一种更加简单有趣的写法,使用with语句来替代try...finally代码块和close()方法

with open(r'c:\text\xiaoqi.txt') as fileReader:
print(fileReader.read())

利用read()一次将文件内容读到内存,但是如果文件过大,将会出现内存不足的问题。一般对于大文件,可以重复调用read(size)方法,一次最多读取size个字节。如果文件是文本文件,Python提供了更加合理的做法,调用了readline()可以每次读取一行内容,调用readlines()一次读取所有内容并按行返回列表。大家可以根据自己的具体需求采取不同的读取方式:

  1. 小文件可以直接采取read()方法读到内存;
  2. 大文件更加安全的方法是连续调用read(size);
  3. 面对于配置文件等文本文件,使用readlines()方法更加合理
with open(r'c:\\text\\ss.txt') as fileReader:
for line in fileReader.readlines():
print(line.strip())

文件写入

写文件和读文件是一样的,唯一的区别实在调用open方法时,传入标识符w或者wb表示写入文本文件或者写入二进制文件,示例如下:

f = open(r'c:\text\qie.txt', 'w')
f.write('xiaoqi')
f.close()

我们可以反复调用write()方法写入文件,最后必须使用close()方法来关闭文件。使用write()方法的时候,操作系统不是立即将数据写入文件中的,而是先写入内存中缓存起来,等到空闲时候再写入文件中,最后使用close()方法就将数据完整地写入文件中了。当然也可以使用f.flush()方法,不断地将数据立即写入文件中,最后使用close()方法来关闭文件。和读文件同样道理,文件操作中可能会出现IO异常,所以还是推荐使用with语句:

with open(r'c:\text\csd.txt', 'w') as fileWriter:
fileWriter.write('sdfs')

file-like Object

open()函数返回的这种有个read()方法的对象,在Python中统称为file-like Object,除了file外,还可以是内存的字节流,网路流,自定义流等。file-like Object不要求从特定类继承,只要写个read()方法就行。

StringIO就是内存中创建的file-like Object,常用作临时缓冲。

二进制文件

一般我们用open()读取的是文本文件,并且是UTF-8编码的文本文件。要读取二进制文件,比如图片、视频,就需要用rb模式打开文件:

f = open("/Users/michael/test.jpg", 'rb')
f.read()
b'\xff\xd8\xff\xe1\x00\x18Exif\x00\x00...' # 十六进制表示的字节

字符编码

要读取非UTF-8编码的文本文件,需要给open()函数传入encoding参数,例如,读取GBK编码的文件:

f = open("/Users/michael/gbk.text", "r", encoding="gbk")
f.read()
'测试'

遇到有些编码不规范的文件,你可能会遇到UnicodeDecodeError,因为在文本文件中可能夹杂了一些非法编码的字符。遇到这种情况,open()函数还接收一个errors参数,表示如果遇到编码错误后如何处理。最简单的方式是直接忽略:

f = open('/Users/michael/gbk.txt', 'r', encoding='gbk', errors='ignore')

StringIO

很多时候,数据读写并不一定是文件也可以在内幕才能中读写。

StringIO顾名思义就是在内存中读写str。

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

>>>from io import StringIO
>>>f = StringIO()
>>>f.write('hello')
5
>>>f.write(" ")
1
>>>f.write("world!")
6
>>>print(f.getvalue()) #getvalue()方法用于获得写入后的str
'hello world!'

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

>>>from io import StringIO
>>>f = StringIO("Hello!\nGoodbye!")
>>>while True:
s = f.readline()
if s == " ":
break
print(s.strip())
Hello!
Hi!
Goodbye

BytesIO

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

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

>>>from io import BytesIO
>>>f = BytesIO()
>>>f.write('中文'.encode("utf-8"))
6
>>>print(f.getvalues)
b'\xe4\xb8\xad\xe6\x96\x87'

注意:写入的不是str,而是经过UTF-8编码的bytes。

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

>>>from io import BytesIO
>>>f = BytesIO(b'\xe4\xb8\xad\xa6\x96\x87')
>>>f.read()
b'\xe4\xb8\xad\xe6\x96\x87'

参考

  1. 廖雪峰-IO编程
  2. Python学习记录之:IO编程
  3. Python中的str与unicode处理方法

python_IO编程的更多相关文章

  1. 从直播编程到直播教育:LiveEdu.tv开启多元化的在线学习直播时代

    2015年9月,一个叫Livecoding.tv的网站在互联网上引起了编程界的注意.缘于Pingwest品玩的一位编辑在上网时无意中发现了这个网站,并写了一篇文章<一个比直播睡觉更奇怪的网站:直 ...

  2. JavaScript之父Brendan Eich,Clojure 创建者Rich Hickey,Python创建者Van Rossum等编程大牛对程序员的职业建议

    软件开发是现时很火的职业.据美国劳动局发布的一项统计数据显示,从2014年至2024年,美国就业市场对开发人员的需求量将增长17%,而这个增长率比起所有职业的平均需求量高出了7%.很多人年轻人会选择编 ...

  3. 读书笔记:JavaScript DOM 编程艺术(第二版)

    读完还是能学到很多的基础知识,这里记录下,方便回顾与及时查阅. 内容也有自己的一些补充. JavaScript DOM 编程艺术(第二版) 1.JavaScript简史 JavaScript由Nets ...

  4. [ 高并发]Java高并发编程系列第二篇--线程同步

    高并发,听起来高大上的一个词汇,在身处于互联网潮的社会大趋势下,高并发赋予了更多的传奇色彩.首先,我们可以看到很多招聘中,会提到有高并发项目者优先.高并发,意味着,你的前雇主,有很大的业务层面的需求, ...

  5. C#异步编程(一)

    异步编程简介 前言 本人学习.Net两年有余,是第一次写博客,虽然写的很认真,当毕竟是第一次,肯定会有很多不足之处, 希望大家照顾照顾新人,有错误之处可以指出来,我会虚心接受的. 何谓异步 与同步相对 ...

  6. UE4新手之编程指南

    虚幻引擎4为程序员提供了两套工具集,可共同使用来加速开发的工作流程. 新的游戏类.Slate和Canvas用户接口元素以及编辑器功能可以使用C++语言来编写,并且在使用Visual Studio 或 ...

  7. C#与C++的发展历程第三 - C#5.0异步编程巅峰

    系列文章目录 1. C#与C++的发展历程第一 - 由C#3.0起 2. C#与C++的发展历程第二 - C#4.0再接再厉 3. C#与C++的发展历程第三 - C#5.0异步编程的巅峰 C#5.0 ...

  8. 猫哥网络编程系列:HTTP PEM 万能调试法

    注:本文内容较长且细节较多,建议先收藏再阅读,原文将在 Github 上维护与更新. 在 HTTP 接口开发与调试过程中,我们经常遇到以下类似的问题: 为什么本地环境接口可以调用成功,但放到手机上就跑 ...

  9. 关于如何提高Web服务端并发效率的异步编程技术

    最近我研究技术的一个重点是java的多线程开发,在我早期学习java的时候,很多书上把java的多线程开发标榜为简单易用,这个简单易用是以C语言作为参照的,不过我也没有使用过C语言开发过多线程,我只知 ...

随机推荐

  1. Linux批量杀死包括某个keyword的进程

    ps -ef|grep ./amplxe-gui|grep -v grep|cut -c 9-15|xargs kill -9 批量杀死包括keyword"./amplxe-gui" ...

  2. 前端(各种demo)三:优惠券,热区,等模块的实现(css方式)

    各种样式的css实现 1.优惠券样式的实现: 2.热区的实现:   在电商平台上总会发出各种券,需要对应到不同的产品,对应到不同的服务.而使用券可以使用UED的设计稿里的照片,但是本来一次性的加载过多 ...

  3. (转)java内部类详解

    本文转自http://www.cnblogs.com/dolphin0520/p/3811445.html,谢谢作者 说起内部类这个词,想必很多人都不陌生,但是又会觉得不熟悉.原因是平时编写代码时可能 ...

  4. Spring MVC如何测试Controller(使用springmvc mock测试)

    在springmvc中一般的测试用例都是测试service层,今天我来演示下如何使用springmvc mock直接测试controller层代码. 1.什么是mock测试? mock测试就是在测试过 ...

  5. MPSOC之8——启动及错误处理

    有了BOOT.BIN(fsbl+pmu+atl+uboot).uImage.uramdisk.image.gz,dtb文件,就可以启动了.把上述文件统统拷贝到SD卡,并设置开发板为SD卡启动. 0. ...

  6. Mac 终端—不同文件不同颜色显示,提示文字

    原文地址 修改Mac终端(Terminal)里不同类型文件的显示颜色 修改Mac终端(Terminal)的提示文字 Mac终端显示/隐藏文件命令 1. 修改Mac终端(Terminal)里不同类型文件 ...

  7. java.lang.StringBuilder和java.lang.StringBuffer (JDK1.8)

    这两个类都是继承自AbstractStringBuilder,AbstractStringBuilder有两个成员属性 char[] value; int count; 前者用于存储字符串,后者用于统 ...

  8. 关于博客中引用多媒体出现的bug说明

    插件说明 Aplayer.Dplayer @DIYgod 大佬在gihub的开源项目,对此,表示非常之感谢!! Aplayer 支持放在页首 支持放在页尾 但是不支持直接放在文章中引用 解决方法: 1 ...

  9. Python并发实践_01_线程与进程初探

    进程与线程 在多任务处理中,每一个任务都有自己的进程,一个任务会有很多子任务,这些在进程中开启线程来执行这些子任务.一般来说,可以将独立调度.分配的基本单元作为线程运行,而进程是资源拥有的基本单位. ...

  10. R语言命令行参数

        批量画图任务中,需要在R中传入若干参数,之前对做法是在perl中每一个任务建立一个Rscript,这种方式超级不cool,在群里学习到R的@ARGV调用方式,差不多能够达到批量任务的要求: a ...