zoukankan      html  css  js  c++  java
  • Python 文件操作

    文件IO常见操作,open()函数,open函数各个参数(mode、buffering、encoding、errors、newline、closefd)、文件指针、缓冲区、上下文管理一一介绍并举例。

    文件IO常见操作:

    Open()函数:

    open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
    打开一个文件,返回一个文件对象(流对象)和文件描述符。打开文件失败,则返回异常

    基本使用:

    创建一个文件test,然后打开它,用完关闭

    参数:file

    open 的file 参数:

    打开或者要创建的文件名。如果不指定路径,默认是当前路径

    In [1]: f = open('c:\test.txt') #file对象,文件不存在返回异常 FileNotFoundError: [Errno 2] No such file or directory: 'c:\test.txt'
    
    In [2]: f = open('c:\test') #打开文件
    
    In [3]: f
    
    Out[3]: <_io.TextIOWrapper name='test6' mode='w' encoding='cp936'> #windows默认cp936(code page),也就是GBK编码
    
    Out[112]: <_io.TextIOWrapper name='test6' mode='w' encoding='UTF-8'> #linux默认是UTF-8编码
    
    In [4]: f.read() #读取文件
    
    In [5]: f.close() #关闭文件
    

     

    参数:mode 模式

    文件操作中,最常见的操作就是读和写。
    文件访问的模式有两种:文本模式二进制模式。不同模式下,操作函数不尽相同,表现的结果也不一样。

    下面依次举例介绍每个描述字符意义:

    open 默认是只读模式r打开已经存在的文件

    在上面的例子中,可以看到默认是文本打开模式,且是只读的。

    r模式 (默认只读)
    
    In [12]: f = open('c:	est') #默认只读打开
    
    In [13]: f.read() #空文件
    Out[13]: ''
    
    In [14]: f.write('mag') #只读模式尝试写入内容返回异常 UnsupportedOperation: not writable
    
    In [15]: f.close() #关闭文件
    
     
    In [16]: f = open('c:	est','r') # 'r' 模式可写可不写,默认就是只读模式
    
    In [17]: f.write('mag') #同样返回异常UnsupportedOperation: not writable
    
    In [18]: f.close() #关闭文件
    
     
    
    w模式(只写)
    
    In [19]: f = open('c:	est','w') #只写方式打开
    
    In [20]: f.read() #不支持读取,异常:UnsupportedOperation: not readable
    
    In [21]: f.write('mag')
    Out[21]: 3
    
    In [22]: f.close() #关闭文件
    
    In [13]: !TYPE test #看看内容,ipython下可以使用!TYPE或者!cat 分别调用windows和linux下查看文件内容命令
    
    mag
    
    In [35]: f.closed #closed属性可以判断文件是否已经关闭,True表示已关闭,Flase未关闭
    Out[35]: True
    
     
    
    In [43]: f = open('test1','w') #如果文件不存在,会创建并打开
    
    In [45]: f.write('magedu')
    Out[45]: 6
    
    In [46]: f.close() #关闭文件
    
    In [47]: !TYPE test1
    
    magedu
    

      

    r
    只读打开文件,如果使用write方法,会抛异常 UnsupportedOperation: not writable
    如果文件不存在,抛出 FileNotFoundError 异常

    w
    表示只写方式打开,如果读取则抛异常 UnsupportedOperation: not readable
    如果文件不存在,则直接创建文件
    如果文件存在,则清空文件内容

    In [48]: f = open('test2','x') #不存在则创建
    
    In [49]: f.read() #'x' 模式可写,不可读 异常:UnsupportedOperation: not readable
    
    In [50]: f.write('python')
    Out[50]: 6
    
    In [51]: f.close() #关闭文件
    
     
    
    In [52]: f = open('test2','x') #文件已存在抛异常:FileExistsError: [Errno 17] File exists: 'test2'
    

      

    x
    文件不存在,创建文件,并只读方式打开
    文件存在,抛出异常 FileExistsError

    In [59]: !TYPE test2
    
    python
    
    In [60]: f = open('test2','a') #已存在文件
    
    In [61]: f.read() #异常 UnsupportedOperation: not readable
    
    In [62]: f.write('
     hello')
    Out[62]: 5
    
    In [63]: f.close() #关闭文件
    
    In [64]: !TYPE test2
    python
    hello
    
     
    
    In [65]: f = open('test3','a') #文件不存在则创建,不可读,可写
    
    In [66]: f.read() #异常UnsupportedOperation: not readable
    
    In [67]: f.write('world')
    Out[67]: 5
    
    In [68]: f.close() #关闭文件
    
    In [69]: !TYPE test3
    world
    

      

    a
    文件存在,只写打开,追加内容
    文件不存在,则创建后,只写打开,追加内容

    r是只读,wxa都是只写。
    wxa都可以产生新文件,w不管文件存在与否,都会生成全新内容的文件;a不管文件是否存在,都能在打开的文件尾部追加;x必须要求文件事先不存在,自己造一个新文件

    文本模式t
    字符流,将文件的字节按照某种字符编码理解,按照字符操作。open的默认mode就是rt。

    二进制模式b
    字节流,将文件就按照字节理解,与字符编码无关。二进制模式操作时,字节操作使用bytes类型

    In [70]: f = open('test3','rb') #二进制只读
    
    In [71]: s = f.read()
    
    In [72]: print(type(s))
    <class 'bytes'>
    
    In [73]: print(s)
    b'world'
    
    In [74]: f.close() #关闭文件
    
     
    
    In [75]: f = open('test3','wb') #IO对象
    
    In [76]: s = f.write('马哥教育'.encode()) #'b' 二进制模式必须使用b'马哥教育'或者encode()转成bytes类型
    
    In [77]: print(type(s)) #'int'类型
    <class 'int'>
    
    In [78]: print(s) #返回是什么
    12
    
    In [79]: f.close() #关闭文件
    
    In [80]: !TYPE test3
    椹�摜鏁欒偛 #乱码原因后面介绍
    
    In [87]: f = open('test3','x+') #'x' 只能打开不存在文件,否则返回异常 FileExistsError
    
    In [88]: f = open('test4','x+')
    
    In [89]: f.write('devops')
    Out[89]: 6
    
    In [90]: f.read() #思考:上一步已经写入,为什么读取不到?(缓冲区,需要flush)
    Out[90]: ''
    
    In [91]: f.close()
    
    In [92]: !type test4
    devops
    

      

    +
    为r、w、a、x提供缺失的读写功能,但是,获取文件对象依旧按照r、w、a、x自己的特征

    +不能单独使用,可以认为它是为前面的模式字符做增强功能的。

    概念:文件指针


    上面的例子中,已经说明了有一个指针。
    文件指针,指向当前字节位置

    mode=r,指针起始在0
    mode=a,指针起始在EOF

    tell()方法  显示指针当前位置
    seek(offset[,whence])方法  移动文件指针位置。offset偏移多少字节,whence从哪里开始。

    文本模式下
    whence 0 缺省值,表示从头开始,offset只能正整数
    whence 1 表示从当前位置,offset只接受0
    whence 2 表示从EOF开始,offset只接受0
    # 文本模式
    
    In [130]: f = open('test5','r+')
    
    In [131]: f.tell() # 起始
    Out[131]: 0
    
    In [132]: f.read()
    Out[132]: 'secopsmetasploit'
    
    In [133]: f.tell() # EOF
    Out[133]: 16
    
    In [134]: f.seek(0) #指针移到起始
    Out[134]: 0
    
    In [135]: f.read()
    Out[135]: 'secopsmetasploit'
    
    In [136]: f.seek(2,0)
    Out[136]: 2
    
    In [137]: f.tell()
    Out[137]: 2
    
    In [138]: f.read()
    Out[138]: 'copsmetasploit'
    
    In [139]: f.seek(2,1) #offset只能为0
    UnsupportedOperation: can't do nonzero cur-relative seeks
    
    In [140]: f.seek(2,2) #offset只能为0
    UnsupportedOperation: can't do nonzero end-relative seeks
    
    In [141]: f.close()
    

      

    二进制模式下
    whence 0 缺省值,表示从头开始,offset只能正整数
    whence 1 表示从当前位置,offset可正可负
    whence 2 表示从EOF开始,offset可正可负
    EOF(end of file,即文件结尾,终点)
    #二进制模式
    
    In [111]: f = open('test5','r+b')
    
    In [112]: f.tell() #起始
    Out[112]: 0
    
    In [113]: f.read() #读取完指针移到EOF
    Out[113]: b'secops'
    
    In [114]: f.tell() #EOF
    Out[114]: 6
    
    In [115]: f.write(b'metasploit')
    Out[115]: 10
    
    In [116]: f.tell()
    Out[116]: 16
    
    In [117]: f.seek(0) #移到起始
    Out[117]: 0
    
    In [118]: f.seek(2,1) #当前位置向后偏移2位
    Out[118]: 2
    
    In [119]: f.read()
    Out[119]: b'copsmetasploit'
    
    In [120]: f.seek(-2,1) #当前位置向前偏移2位
    Out[120]: 14
    
    In [121]: f.seek(-3,1)
    Out[121]: 11
    
    In [122]: f.seek(2,2) #从EOF开始
    Out[122]: 18
    
    In [123]: f.seek(0)
    Out[123]: 0
    
    In [125]: f.seek(-2,1) #异常,向前偏移不可越界
    OSError: [Errno 22] Invalid argument
    
    In [126]: f.tell()
    Out[126]: 0
    
    In [127]: f.read()
    Out[127]: b'secopsmetasploit'
    
    In [128]: f.seek(-20,2) #异常,向前偏移不可越界
    OSError: [Errno 22] Invalid argument
    
    In [129]: f.close()
    

      

    二进制模式支持任意起点的偏移,从头、从尾、从中间位置开始。
    向后seek可以超界,但是向前seek的时候,不能超界,否则抛异常。

    参数:buffering 缓冲区

    -1 表示使用缺省大小的buffer。
    如果是二进制模式,使用 io.DEFAULT_BUFFER_SIZE 值(缺省缓冲区大小,字节),默认是4096或者8192 字节。
    如果是文本模式,或者终端设备,是行缓存模式,如果不是,则使用二进制模式的策略。
    0 只在二进制模式使用,表示关buffer
    1 只在文本模式使用,表示使用行缓冲。意思就是见到换行符就flush
    大于1 用与指定buffer的大小,如果不指定或者负数,表示使用缺省大小


    flush() 将缓冲区数据写入磁盘
    close() 关闭前会调用flush()

    buffer 缓冲区
    缓冲区一个内存空间,一般来说是一个FIFO队列(file input file output),到缓冲区满了或者达到阈值,数据才会flush到磁盘

    In [142]: import io
    
    In [143]: io.DEFAULT_BUFFER_SIZE   #系统默认buffer大小
    Out[143]: 8192
    

      

    buffering 说明
    buffering=-1 t和b,都是 io.DEFAULT_BUFFER_SIZE 大小
    buffering=0 b关闭缓冲区
    t不支持  (文件模式简写t)
    buffering=1 b就1个字节
    t行缓冲,遇到换行符才flush
    buffering>1 b模式表示行缓冲大小。缓冲区的值可以超过 io.DEFAULT_BUFFER_SIZE,直到设定的值超过后才把缓冲区flush
    t模式,是 io.DEFAULT_BUFFER_SIZE,flush完后把当前字符串也写入磁盘

    似乎看起来很麻烦,一般来说,只需要记得:
    文本模式,一般都用默认缓冲区大小
    二进制模式,是一个个字节的操作,可以指定buffer的大小
    一般来说,默认缓冲区大小是个比较好的选择,除非明确知道,否则不调整它
    一般编程中,明确知道需要写入硬盘了,都会手动调用依次flush,而不是等到自动flush或者close的时候


    参数:encoding 编码,仅文本模式使用

    None 表示使用缺省编码,依赖操作系统。win、linux下测试如下代码

    In [148]: f = open('test6','w')
    
    In [149]: f
    Out[149]: <_io.TextIOWrapper name='test6' mode='w' encoding='cp936'> #linux下是UTF-8
    
    In [150]: f.write('啊')
    Out[150]: 1
    
    In [151]: f.close()
    

      

    其它参数:


    errors:什么样的编码错误将被捕获
    None和strict表示有编码错误将抛出ValueError异常;ignore表示忽略

    newline:文本模式中,换行的转换。可以为None、''、' '、' '、' '
    读时,None表示 ' '、' '、' ' 都将转换为' ';'' 表示不会不会自动转换通用换行符;其它合法字符表示换行符就是指定字符,就会按照指定字符分行
    写时,None表示' '(win)或' '(linux)都会被替换为系统缺省行分割符os.linesep;' '或''表示' '不转换;其它合法字符表示' '(win)或' '(linux)会被替换为指定的字符

    In [155]: import os
    
    In [156]: os.linesep
    Out[156]: ' '


    closefd:关闭文件描述符,True表示关闭它。False会在文件关闭后保持这个描述符。
    fileobj.fineno()查看

      

    read方法

    read(size=-1)
    size 表示读取的多少个字符或字节;负数或者None表示读到EOF

    readline方法 行读取

    readline(size=-1)
    一行行读取文件内容。size设置依次能够读取行内几个字符或者字节。
    readlines(hin=-1)
    读取所有行的列表。指定hint则返回指定的行数。

    close方法

    flush并关闭文件对象。
    文件已经关闭,再次关闭没有任何效果。


    其他方法
    seekable() 是否可seek
    readable() 是否可读
    write() 是否可写
    closed 是否已经关闭

    上下文管理

    问题的引出
    在linux中,执行

    (3.5.3/envs/magedu353) [python@ihoneysec cmdb]$ touch test
    (3.5.3/envs/magedu353) [python@ihoneysec cmdb]$ vim context.py #写入以下代码
    lst = []
    for _ in range(2000):
    lst.append(open('test'))
    print(len(lst))
      
    
    (3.5.3/envs/magedu353) [python@ihoneysec cmdb]$ python context.py
    Traceback (most recent call last):
    File "context.py", line 3, in <module>
    OSError: [Errno 24] Too many open files: 'test'
    (3.5.3/envs/magedu353) [python@ihoneysec cmdb]$ lsof|wc -l 1068

      


    lsof 列出打开的文件(list open files)
    $ lsof |grep test|wc -l
    ulimit -a查看所有限制。其中open files就是打开文件数的限制,默认1024
    $ ulimit -n 65535 #可以修改为65535,但要根据硬件资源调整为合适的大小

    for x in lst:
        zx.close()
    

      

    将文件依次关闭,然后就可以继续打开了。再看一次lsof。

    如何解决?
    1、异常处理
    当出现异常的时候,拦截异常。但是,因为很多代码都可能出现OSError异常;还不好判断异常就时因为资源限制产生的

    f = open('test')
    try:
        f.write('abc') #文件只读,写入失败
    finally:
        f.close() #finally 可以保证打开的文件可以被关闭。
    

      


    2、上下文管理
    一种特殊的语法,交给解释器取释放文件对象

    with open('test6') as f:
        f.write('abc')
        f.closed #测试f是否关闭
    

      

    上下文管理
    使用with..as 关键字
    上下文管理的语句块并不会开启新的作用域
    with语句块执行完的时候,会自动关闭文件对象

    对于类似于文件对象的IO对象,一般来说都需要在不使用的时候关闭、注销,以释放资源。
    IO被打开的时候,会获得一个文件描述符。计算机资源是有限的,所有操作系统都会做限制。
    就是为了保护计算机的资源不要被完全耗尽,计算机资源是共享的,不是独占的。
    一般情况下,除非特别明确的知道资源情况,否则不要提高资源的限制值来解决问题。

  • 相关阅读:
    欧拉公式求四面体的体积
    欧拉公式求四面体的体积
    I
    I
    闭包传递(floyed)
    闭包传递(floyed)
    Python hypot() 函数
    Python cos() 函数
    Python atan2() 函数
    Python atan() 函数
  • 原文地址:https://www.cnblogs.com/i-honey/p/7736210.html
Copyright © 2011-2022 走看看