【Python】常用的文件管理操作细节讲解

文章目录

  • 文件的基础操作
  • 打开/关闭文件
  • 关于内建函数:
  • 关于文件对象:
  • 读文件
  • 写文件
  • 关于读写缓冲区
  • 操作文件指针
  • 文件对象内建属性
  • with语句和上下文管理器
  • 文件系统的基础操作
  • 文件路径操作
  • 常用文件系统操作
  • 本文主要内容:

  • 掌握文件基本操作
  • 掌握文件系统基本操作
  • 够结合之前学习的知识, 写出一些实用程序.

  • 本文作者链接:https://blog.csdn.net/chuxinchangcun?spm=1019.2139.3001.5343 (反爬)

    文件的基础操作

    打开/关闭文件

    内建函数open, 能够打开一个指定路径下的文件, 返回一个文件对象.

    open最常用的有两个参数, 第一个参数是文件名(绝对路径或者相对路径), 第二个是打开方式

  • ‘r’/‘w’/‘a’/‘b’,表示读(默认)/写/追加写/二进制.
  • 注意:打开文件一定要记得关闭
  • a = open('Z:/test.txt','r')	#注意不是反斜杠,Z盘要大写
    a.close()	#关闭文件
    

    关于内建函数:

    我们反复遇到了 “内建函数” 这个词. 内建函数其实是包含在 __builtins__ 这个模块中的一些函数.

    而 _builtins_ 这个模块Python解释器会自动包含.

    使用 dir(_builtins_) 可以看到Python中一共有哪些内建函数

    print(dir(__builtins__))
    #执行结果:
    ['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning', 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError', 'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FileExistsError', 'FileNotFoundError', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError', 'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'ModuleNotFoundError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError', 'RecursionError', 'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning', 'StopAsyncIteration', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'WindowsError', 'ZeroDivisionError', '__build_class__', '__debug__', '__doc__', '__import__', '__loader__', '__name__', '__package__', '__spec__', 'abs', 'all', 'any', 'ascii', 'bin', 'bool', 'breakpoint', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'exit', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']
    

    关于文件对象:

    我们学习C语言知道 FILE* , 通过 FILE* 进行文件读写操作.

    我们学习Linux时又知道, FILE 结构中其实包含了文件描述符*, 操作系统是通过文件描述符来对文件操作

    Python的文件对象, 其实也包含了文件描述符, 同时也包含了这个文件的一些其他属性. 本质上也是通过文件描述符完成对文件的读写操作.

    既然文件对象包含了文件描述符, 我们知道, 一个进程可操作的文件描述符的数目是有上限的. 因此对于
    完了的文件描述符要及时关闭.


    当文件对象被垃圾回收器销毁时, 也会同时释放文件描述符.

    如果文件打开失败(例如文件不存在), 就会执行出错

    a = open('Z:\XXX','r')
    #执行结果:
    FileNotFoundError: [Errno 2] No such file or directory: 'Z:\\XXX'
    
    

    读文件

    read: 读指定长度字节数的数据, 返回一个字符串.

    a = open('Z:/test.txt','r')
    print(a.read())
    #执行结果:
    hello world
    hello python
    

    readline: 读取一行数据, 返回一个字符串 本文作者链接:https://blog.csdn.net/chuxinchangcun?spm=1019.2139.3001.5343 (反爬)

    a = open('Z:/test.txt','r')
    print(a.readline())  #hello world
    

    readlines: 读取整个文件, 返回一个列表. 列表中的每一项是一个字符串, 代表了一行的内容

    a = open('Z:/test.txt','r')
    print(a.readlines())	#['hello world\n', 'hello python']
    

    直接使用for line in f的方式循环遍历每一行, 功能和readline类似. 一次只读一行,

    相比于readlines占用内存少, 但是访问IO设备的次数会增多, 速度较慢

    a = open('Z:/test.txt','r')
    for line in a:
        print(line)
    #执行结果:
    hello world
    
    hello python
    

    注意, readline或者readlines这些函数仍然会保留换行符. 所以我们往往需要写这样的代码来去掉换行符.

    a = open('Z:/test.txt','r')
    # for line in f 的方式循环遍历每一行, 功能和readline类似,返回的line是字符串,所以可以使用字符串的成员函数
    for line in a:	
        print(line.strip())
    #执行结果:
    hello world
    hello python
    
    
    #或者:使用列表解析语法
    a = open('Z:/test.txt','r')
    data = [line.strip() for line in a.readlines()]
    print(data)	#['hello world', 'hello python']
    

    readlines和for line in f: 的区别:

    第一种方法是全部读取->只读取一次 时间快,但是占空间。第二种方式是隔行读取 ->读取多次,时间慢,但是省空间。读取大文件选方式2


    写文件

    write: 向文件中写一段字符串
    本文作者链接:https://blog.csdn.net/chuxinchangcun?spm=1019.2139.3001.5343 (反爬)

  • 如需写文件, 必须要按照 ‘w’ 或者 ‘a’ 的方式打开文件. 否则会写失败.
  • a = open('Z:/test.txt','r')
    a.write("hello Mango")	#io.UnsupportedOperation: not writable
    

    a = open('Z:/test.txt','w')
    a.write("hello Mango")	#用w方式打开,原文件的内容被删除
    

    image-20220320144757014


    a = open('Z:/test.txt','a')
    a.write("hello Lemon")	#以a的方式打开->追加
    

    image-20220320144851497

    writelines: 参数是一个列表, 列表中的每一个元素是一个字符串.

    a = open('Z:/test.txt','w')
    w = ['Mango\n','hello\n',' world\n']
    a.writelines(w)#把列表的内容写入到文件中
    

    image-20220320145231050

    并没有一个 writeline 这样的函数. 因为这个动作等价于 write 时在字符串后面加上 ‘\n’. 同理, 使用
    writelines的时候, 也需要保证每一个元素的末尾, 都带有 ‘\n’


    关于读写缓冲区

    学习Linux我们知道, C语言库函数中的fread, fwrite和系统调用read, write相比, 功能是类似的. 但是
    fread/fwrite是带有缓冲区的

    Python的文件读写操作, 既可以支持带缓冲区, 也可以选择不带缓冲区.

    在使用open函数打开一个文件的时候, 其实还有第三个参数, 可以指定是否使用缓冲区, 以及缓冲区的大小是多少 (查看 help(open) 以及 print(_doc_) ).

    a  = open('Z:/test.txt','r')
    print(a.__doc__)
    print(help(open))
    

    本文作者链接:https://blog.csdn.net/chuxinchangcun?spm=1019.2139.3001.5343 (反爬)

    使用flush方法可以立即刷新缓冲区


    操作文件指针

    文件具备随机访问能力. 这个过程是通过操作文件指针完成的.

    seek: 将文件指针移动到从文件开头算起的第几个字节上. 有两个参数.

    第一个参数offset表示偏移的字节数.

    第二个参数whence表示偏移量的起始位置在哪. 值为0, 表示从开头计算, 值为1, 表示从当前位置, 值为2, 表示从文件结尾位置.

    tell: 获取当前文件指针指向的位置. 返回当前位置到文件开头的偏移量.


    文件对象内建属性

    image-20220319092256112


    with语句和上下文管理器

    本文作者链接:https://blog.csdn.net/chuxinchangcun?spm=1019.2139.3001.5343 (反爬)
    我们刚才说了, 用完的文件对象, 要及时关闭, 否则可能会引起句柄泄露.

    但是如果逻辑比较繁琐, 或者我们忘记了手动调用close怎么办?

    def func():
        f = open('Z:/test.txt','r')
        x =10
        if x==10:
            return
        #执行文件操作
        f.close()	#上面提前return,导致内存泄漏
    

    解决:在每一个return前先关闭文件

    def func():
        f = open('Z:/test.txt','r')
        x =10
        if x==10:
            f.close()
            return
        #执行文件操作
        f.close()
    

    但是如果抛出异常也会导致文件没有关闭:

    def func():
        f = open('Z:/test.txt','r')
        x =10
        a = [1,2,3]
        print(a[100])	#越界:IndexError: list index out of range
        if x==10:
            f.close()
            return
        #执行文件操作
        f.close()
        
    func()
    

    C++中使用 “智能指针” 这样的方式来管理内存/句柄的释放, 借助对象的构造函数和析构函数, 自动完成释
    放过程.

    但是Python中对象的回收取决于GC机制, 并不像C++中时效性那么强.

    Python中引入了上下文管理器来解决这类问题.

    def func():
        with open('Z:/test.txt','r') as f:	#上下文管理器
            #文件操作
            pass    #空语句
    

    可以更改编码格式:

    with open('Z:/test.txt', 'r',encoding='utf-8') as f:
        print(f.readline())
    

    with open('Z:/test.txt', 'r',encoding='utf-8') as f:
        for line in f:
            print(line.strip())
    #执行结果:
    Mango
    hello
    world
    

    在with语句块内进行文件操作. 当文件操作完毕之后, 出了with语句之外. 就会自动执行f的关闭操作.

    一个支持上下文协议的对象才能被应用于with语句中. 我们将这种对象称为上下文管理器. Python中很多
    内置对象都是上下文管理器, 例如文件对象, 线程锁对象等.


    文件系统的基础操作

    文件路径操作

    os.path这个模块中, 包含了一些实用的路径操作的函数

    basename:去掉目录路径,返回文件名

    dirname:去掉文件名,返回目录路径

    import os.path
    p = '/aaa/bbb/ccc.txt'
    print(os.path.dirname(p))   # /aaa/bbb
    print(os.path.basename(p))  #ccc.txt
    

    split:返回(dirname(),basename())的元组
    本文作者链接:https://blog.csdn.net/chuxinchangcun?spm=1019.2139.3001.5343 (反爬)

    import os.path as path
    p = '/aaa/bbb/ccc.txt'
    print(path.split(p))	#('/aaa/bbb', 'ccc.txt')
    

    splitext:返回(filename,extension)元组 extension:文件的后缀名

    import os.path as path
    p = '/aaa/bbb/ccc.txt'
    print(path.splitext(p))#('/aaa/bbb/ccc', '.txt')
    

    exists:返回文件是否存在

    import os.path as path
    p = '/aaa/bbb/ccc.txt'
    print(path.exists(p))   #False
    p = 'Z:/test.txt'
    print(path.exists(p))   #True
    

    分隔

    image-20220319092518536


    信息

    image-20220319092532233


    查询

    image-20220319092542798


    常用文件系统操作

    os模块中包含了很多对文件/目录的基础操作, 参见下表.

    walk:生成一个目录树下的所有文件名

  • 返回的是一个三元组:当前目录,当前目录下的目录,当前目录含有哪些文件
  • 自动完成递归
    本文作者链接:https://blog.csdn.net/chuxinchangcun?spm=1019.2139.3001.5343 (反爬)
  • import os.path as path
    import os
    p = 'Z:/test'
    for item in os.walk(p):
        print(item)
    #执行结果:
    ('Z:/test', ['a', 'b'], [])
    ('Z:/test\\a', ['aa'], [])
    ('Z:/test\\a\\aa', [], ['aa.txt'])
    ('Z:/test\\b', ['c'], ['b.txt'])
    ('Z:/test\\b\\c', [], ['c.txt'])
    

    因为返回的是三元组,所以可以写成: 打印完整路径

    base:当前目录

    _ 当前目录中含哪些目录,不需要用,所以用占位符代替

    files:当前目录含有哪些文件

    import os.path as path
    import os
    p = 'Z:/test'
    #打印完整路径
    for base,_,files in os.walk(p):
        for f in files:
            print(base+f)	
    #执行结果:
    Z:/test\a\aaaa.txt
    Z:/test\bb.txt
    Z:/test\b\cc.txt
    

    remove:删除文件

    import os.path as path
    import os
    p = 'Z:/test/'
    print(path.exists(p+'b/b.txt')) #True
    os.remove(p+'b/b.txt')  #删除路径为:  Z:/test/b/b.txt文件
    print(path.exists(p+'b/b.txt')) #False
    

    listdir:列出当前目录的文件

    import os.path as path
    import os
    p = 'Z:/test/'
    print(os.listdir(p))#列出当前目录的文件  #['a', 'b']
    

    rmdir:删除目录

    注意:这个只能删除空目录

    import os.path as path
    import os
    p = 'Z:/test/'
    print(path.exists(p+'a'))   #True
    print(os.listdir(p))#列出当前目录的文件  ['a', 'b']
    print(os.rmdir(p+'a'))  #报错:空目录不能直接删除 OSError: [WinError 145] 目录不是空的。: 'Z:/test/a'
    

    如果想要删除非空目录:使用shutil模块的rmtree函数

    import os.path as path
    import os
    import shutil
    p = 'Z:/test/'
    print(path.exists(p+'a'))   #True
    print(os.listdir(p))#列出当前目录的文件  ['a', 'b']
    shutil.rmtree(p+'a')
    print(os.listdir(p))#列出当前目录的文件  ['b']
    

    文件处理

    image-20220319092619473

    目录/文件夹

    image-20220319092635697


    访问/权限

    image-20220319092647661


    文件描述符操作

    image-20220319092705872


    注意:

    虽然os模块中也提供了open, read, write系列函数, 可以用于读写文件.

    内建open返回的是文件对象. os.open返回的是文件描述符.

    我们实际使用中仍然更推荐使用内建函数open创建文件对象, 并使用文件对象的读写操作来操作文件. 因
    为文件对象使用起来更方便一些.


    来源:芒果再努力

    物联沃分享整理
    物联沃-IOTWORD物联网 » 【Python】常用的文件管理操作细节讲解

    发表评论