zoukankan      html  css  js  c++  java
  • python_IO编程

    本篇文章将介绍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:	extxiaoqi.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:	extqie.txt', 'w')
    f.write('xiaoqi')
    f.close()
    

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

    with open(r'c:	extcsd.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'xffxd8xffxe1x00x18Exifx00x00...' # 十六进制表示的字节
    

    字符编码
    要读取非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!
    Goodbye!")
    >>>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'xe4xb8xadxe6x96x87'
    

    注意:写入的不是str,而是经过UTF-8编码的bytes。
    和StringIO类似,可以用一个bytes初始化BytesIO,然后,像读文件一样读取:

    >>>from io import BytesIO
    >>>f = BytesIO(b'xe4xb8xadxa6x96x87')
    >>>f.read()
    b'xe4xb8xadxe6x96x87'
    

    参考

    1. 廖雪峰-IO编程
    2. Python学习记录之:IO编程
    3. Python中的str与unicode处理方法
  • 相关阅读:
    LeetCode 811. Subdomain Visit Count (子域名访问计数)
    LeetCode 884. Uncommon Words from Two Sentences (两句话中的不常见单词)
    LeetCode 939. Minimum Area Rectangle (最小面积矩形)
    LeetCode 781. Rabbits in Forest (森林中的兔子)
    LeetCode 739. Daily Temperatures (每日温度)
    三种方式实现按钮的点击事件
    239. Sliding Window Maximum
    14.TCP的坚持定时器和保活定时器
    13.TCP的超时与重传
    12.TCP的成块数据流
  • 原文地址:https://www.cnblogs.com/miqi1992/p/8283155.html
Copyright © 2011-2022 走看看