• Python升级之路( Lv9 ) 文件操作


    Python系列文章目录

    第一章 Python 入门
    第二章 Python基本概念
    第三章 序列
    第四章 控制语句
    第五章 函数
    第六章 面向对象基础
    第七章 面向对象深入
    第八章 异常机制
    第九章 文件操作


    前言

    在本章节, 主要介绍了文件操作相关的API方法使用
    首先我们将会学习什么是文件操作, 以及文件分类还有在IO操作时会用到的常用编码介绍
    然后我们学习了文件操作的流程, 创建->写入->关闭
    在然后我们学习了文件的拓展, 序列化模块pickle, 文件操作模块csv, 系统操作调用模块os和os.path以及文件拷贝压缩模块shutil


    一、什么是文件操作

    一个完整的程序一般都包括数据的存储和读取;我们在前面写的程序数据都没有进行实际的存储,因此python解释器执行完数据就消失了
    实际开发中,我们经常需要从外部存储介质(硬盘、光盘、U盘等)读取数据,或者将程序产生的数据存储到文件中,实现“持久化”保存

    1. 文件分类

    按文件中数据组织形式,我们把文件分为文本文件和二进制文件两大类:

    1. 文本文件
      文本文件存储的是普通“字符”文本,python默认为 unicode 字符集,可以使用记事本程序打开

    2. 二进制文件
      二进制文件把数据内容用“字节”进行存储,无法用记事本打开, 必须使用专用的软件解码.
      常见的有:MP4视频文件、MP3音频文件、JPG图片、doc文档等等

    2. 常用编码

    在操作文本文件时,经常会操作中文,这时候就经常会碰到乱码问题.
    为了解决中文乱码问题,需要学习下各个编码之前的问题.

    常用编码之间的关系如下:

    在这里插入图片描述

    ASCII

    全称为 American Standard Code for Information Interchange ,美国信息交换标准代码,
    这是世界上最早最通用的单字节编码系统,主要用来显示现代英语及其他西欧语言

    注意事项:

    • ASCII 码用7位表示,只能表示128个字符. 只定义了2^7=128个字符,用7bit即可完全编码,
      而一字节8bit的容量是256,所以一字节 ASCII 的编码最高位总是0
    • ASCll 码对应码表如下: ASCll 码表

    GBK

    GBK即汉字内码扩展规范,英文全称Chinese Internal Code Specification.
    GBK编码标准兼容GB2312,共收录汉字21003个、符号883个,并提供1894个造字码位,简、繁体字融于一库。
    GBK采用双字节表示,总体编码范围为8140-FEFE,首字节在81-FE 之间,尾字节在40-FE 之间

    Unicode

    Unicode 编码设计成了固定两个字节,所有的字符都用16位2^16=65536表示,包括之前只占8位的英文字符等,所以会造成空间的浪费
    Unicode 完全重新设计,不兼容 iso8859-1 ,也不兼容任何其他编码

    UTF-8

    对于英文字母, unicode 也需要两个字节来表示, 所以 unicode 不便于传输和存储.
    因此而产生了 UTF编码 , UTF-8 全称是( 8-bit UnicodeTransformation Format )

    注意事项

    • UTF 编码兼容 iso8859-1 编码,同时也可以用来表示所有语言的字符
    • UTF 编码是不定长编码,每一个字符的长度从1-4个字节不等.
      英文字母都是用一个字节表示,而汉字使用三个字节
    • 一般项目都会使用 UTF-8
      我们之所以倾向于使用UTF-8 , 是因为其不定长编码可以在节省内存的同时能够完全兼容中文

    二、文件操作

    1. 创建文件对象

    open() 函数用于创建文件对象,基本语法格式如下: open(文件名[,打开方式])

    注意:

    • 如果只是文件名,代表在当前目录下的文件. 文件名可以录入全路径,比如: D:\a\b.txt
      可以使用原始字符串 r“d:\b.txt” 减少 \ 的输入, 因此以上代码可改写成 f = open(r"d:\b.txt","w")

    • 作为入参的打开方式如下(经常会用!!!)
      在这里插入图片描述

    • 文本文件对象和二进制文件对象的创建
      如果是二进制模式 b ,则创建的是二进制文件对象,处理的基本单元是“字节”
      如果没有增加模式 b ,则默认创建的是文本文件对象,处理的基本单元是“字符”

    2. 文件的写入

    文本文件的写入一般就是三个步骤:

    • 创建文件对象
    • 写入数据
    • 关闭文件对象

    基本文件的写入操作

    实操代码

    # 1.使用open()方式
    f = open(r"d:\a.txt", "a")
    s = "TimePause\n时间静止\n"
    f.write(s)
    f.close()
    
    • 1
    • 2
    • 3
    • 4
    • 5

    结果展示

    在这里插入图片描述

    中文乱码

    代码编写时

    windows 操作系统默认的编码是 GBK , Linux 操作系统默认的编码是 UTF- 8 .
    当我们用 open() 时,调用的是操作系统相关api来打开的文件,并且默认的编码是 GBK
    但是由于我们通常习惯将所有代码编码都设置成 UTF- 8 ., 因此在打开时会出现乱码问题, 如下图所示

    在这里插入图片描述
    解决方案:
    按照上图提示, 将文本编码设置成 GBK格式读取即可
    在这里插入图片描述
    注意:
    我们还可以通过指定编码来解决中文乱码问题. 因为我们将pycharm文本读写编码都设置成 utf-8,
    因此只要我们在文件写入的时候规定编码为 utf-8(默认gbk), 那么我们在读取时就不会出现乱码. 如下代码

    实操代码

    # 【示例】通过指定文件编码解决中文乱码问题
    f = open(r"d:\bb.txt", "w", encoding="utf-8")
    f.write("一个有温情的小站\n时间静止不是简史")
    f.close()
    
    • 1
    • 2
    • 3
    • 4

    控制台输出时

    问题描述

    我们一般习惯把pycharm所有字符编码设置成utf-8时. 在我们进行网络请求时, 有时候会返回乱码问题, 如下图

    在这里插入图片描述

    在这里插入图片描述

    问题分析

    因为我们在 pycharm 设置所有字符编码均为 UTF-8, 但是通过网络请求得到GBK格式的文本, 然后我们仍以 UTF-8 编码去解码就会出现乱码

    解决方案

    可以将项目编码设置成GBK格式即可; 也可以通过文本操作代码对得到的数据进行GBK格式读取
    亦或者在写入时, 直接将编码声明为UTF-8

    在这里插入图片描述
    在这里插入图片描述

    write()/writelines()写入数据

    • write(a) :把字符串 a 写入到文件中
    • writelines(b) :把字符串列表写入文件中,不添加换行符

    实操代码

    # 【操作】添加字符串列表数据到文件中
    f = open(r"d:\bb.txt", 'w', encoding="utf-8")
    s = ["什么鬼\n"] * 3		# 通过 \n实现手动换行
    f.writelines(s)
    f.close()
    
    • 1
    • 2
    • 3
    • 4
    • 5

    close()关闭文件流

    由于文件底层是由操作系统控制,所以我们打开的文件对象必须显式调用 close() 方法关闭文件对象.
    当调用 close() 方法时,首先会把缓冲区数据写入文件(也可以直接调用 flush() 方法),再关闭文件,释放文件对象

    注意:

    • close()一般结合异常机制的 finally 一起使用
    • 也可以通过 with 关键字实现无论何种情况都能关闭打开的文件对象(推荐)

    实操代码

    # 【操作】结合异常机制的 finally ,确保关闭文件对象
    # "a" 设置打开方式为追加模式
    try:
        f = open(r"d:\c.txt", "a")
        s = "来自深渊"
        f.write(s)
    except BaseException as e:
        print(e)
    finally:
        f.close()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    with语句(上下文管理器)

    with关键字 (上下文管理器)可以自动管理上下文资源,不论什么原因跳出 with块 ,都能确保文件正确的关闭,
    并且可以在代码块执行完毕后自动还原进入该代码块时的现场

    实操代码

    # 【操作】使用 with 管理文件写入操作
    s = ["齐格飞"] * 3
    with open(r"d:\cc.txt", "w") as f:
        f.writelines(s)
    
    • 1
    • 2
    • 3
    • 4

    3. 文件的读取

    文件读取的步骤:

    • 打开文本文件对象
    • 写入数据

    文件的读取一般使用如下三个方法:

    • read([size]): 从文件中读取 size 个字符,并作为结果返回
      如果没有 size 参数,则读取整个文件. 读取到文件末尾,会返回空字符串

    • readline(): 读取一行内容作为结果返回
      读取到文件末尾,会返回空字符串

    • readlines() : 文本文件中,每一行作为一个字符串存入列表中,返回该列表

    代码格式

    with open(r"d:\a.txt", "r"[, encoding="utf-8"]) as f:
        f.read(4)
    
    • 1
    • 2

    注意:

    • 在读取文件时, 需要注意读写时字符编码的一致性, 如果写的时候没有指定编码(默认GBK), 则在读取的时候也不需要指定编码
    • 但如果读的时候未指定编码, 写的时候指定, 则会报错.
      例如: 写的时候指定 encoding="utf-8",
      则控制台报 UnicodeDecodeError: 'utf-8' codec can't decode byte 0xbc in position 13: invalid start byte

    实操代码

    # 【操作】 读取一个文件前4个字符
    import pickle
    
    with open(r"d:\a.txt", "r") as f:
        print(f.read(4))
    
    # 【操作】文件较小,一次将文件内容读入到程序中
    with open(r"d:\aa.txt", "r") as f:
        print(f.read())
    
    # 【操作】按行读取一个文件
    with open(r"d:\b.txt") as f:
        while True:
            lines = f.readline()
            if not lines:  # 在python 中 if not 会将后面对象隐式转成True或者False进行判断, 因此遇到空字符串也返回False
                break
            else:
                print(lines, end="")
                print()
    
    # 【操作】使用迭代器(每次返回一行)读取文本文件
    # 写和读的编码要对应
    with open(r"d:\bb.txt", "r", encoding="utf-8") as f:
        for a in f:
            print(a, end="")
    
    # 【操作】为文本文件每一行的末尾增加行号
    with open(r"d:\c.txt", "r") as f:
        lines = f.readlines()
        lines2 = [line.rstrip() + " # " + str(index) + "\n" for index, line in zip(range(1, len(lines) + 1), lines)]
        with open(r"d:\c.txt", "w") as ff:
            ff.writelines(lines2)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    二进制文件的读取和写入

    二进制文件的处理流程和文本文件流程一致。首先还是要创建文件对象,
    创建好二进制文件对象后,仍然可以使用 write() 、 read() 实现文件的读写操作

    在创建文件对象时, 首先需要指定二进制模式,然后才能创建出二进制文件对象. 例如

    • f = open(r"d:\a.txt", 'wb') 可写的、重写模式的二进制文件对象
    • f = open(r"d:\a.txt", 'ab') 可写的、追加模式的二进制文件对象
    • f = open(r"d:\a.txt", 'rb') 可读的二进制文件对象

    实操代码

    # 二进制文件的读取和写入(此操作相当于复制)
    # f = open(r"d:\a.txt", 'wb') #可写的、重写模式的二进制文件对象
    # f = open(r"d:\a.txt", 'ab') #可写的、追加模式的二进制文件对象
    # f = open(r"d:\a.txt", 'rb') #可读的二进制文件对象
    with open(r"d:\aaa.png", "rb") as scrFile, open(r"d:\bbb.png", "wb") as destFile:
        for l in scrFile:
            destFile.write(l)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    4. 文件对象的常用属性和方法

    文件对象的属性
    在这里插入图片描述
    文件对象的打开模式

    在这里插入图片描述
    文件对象的常用方法

    在这里插入图片描述

    文件任意位置操作

    利用 seek() 可以将读取文件的指针移动到指定字节位置上
    一个中文字符站两个字节, 而英文只占一个字节

    实操代码

    print("=================文件任意位置操作======================")
    # 【示例】 seek() 移动文件指针示例
    with open(r"d:\cc.txt", "r") as f:
        print("文件名是{0}".format(f.name))  # 文件名是d:\cc.txt
        print(f.tell())  # 0
        print("读取文件的内容", str(f.readline()))  # 读取文件的内容 齐格飞齐格飞齐格飞
        print(f.tell())  # 18
        f.seek(4, 0)  # 中文占2个字节, 因此在seek时需要是2的倍数
        print("文件读取的内容", str(f.readline()))  # 文件读取的内容 飞齐格飞齐格飞
        print(f.tell())  # 18
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    三、文件操作拓展模块

    1. pickle序列化模块

    序列化指的是:将对象转化成“串行化”数据形式,存储到硬盘或通过网络传输到其他地方.
    反序列化是指相反的过程,将读取到的“串行化数据”转化成对象
    可以使用pickle模块中的函数,实现序列化和反序列操作

    序列化我们使用:

    • pickle.dump(obj, file) obj 就是要被序列化的对象, file 指的是存储的文件
    • pickle.load(file) 从 file 读取数据,反序列化成对象

    实操代码

    import pickle
    print("=================使用pickle序列化=======================")
    # 【操作】将对象序列化到文件中
    with open("student.info", "wb") as f:
        name = "时间静止"
        age = 18
        score = [90, 80, 70]
        resume = {"name": name, "age": age, "score": score}
        pickle.dump(resume, f)
    
    # 【操作】将获得的数据反序列化成对象
    with open("student.info", "rb") as f:
        resume = pickle.load(f)
        print(resume)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    2. csv文件的操作

    csv是逗号分隔符文本格式,常用于数据交换、Excel文件和数据库数据的导入和导出

    与Excel文件不同,CSV文件中:

    • 值没有类型,所有值都是字符串
    • 不能指定字体颜色等样式
    • 不能指定单元格的宽高,不能合并单元格
    • 没有多个工作表
    • 不能嵌入图像图表

    Python标准库的模块csv提供了读取和写入csv格式文件的对象

    我们在excel中建立一个简单的表格并且另存为 csv(逗号分隔) ,我们打开查看这个csv文件内容

    在这里插入图片描述
    在这里插入图片描述

    csv文件读取

    实操代码

    import csv
    
    with open(r"d:\workBook.csv") as a:
        o_csv = csv.reader(a)    # #创建csv对象,它是一个包含所有数据的列表,每一行为一个元素
        headers = next(o_csv)   # #获得列表对象,包含标题行的信息
        print(headers)
        for row in o_csv:       # 循环打印各行内容
            print(row)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    结果展示
    在这里插入图片描述

    csv文件写入

    实操代码

    # 【操作】 csv.writer 对象写一个csv文件
    headers = ['姓名', '年龄', '工作', '住址']
    rows = [('JOJO', '18', '按摩师', '英国'), ('迪奥', '19', '老板', '埃及'), ('乔鲁诺乔巴纳', '20', '混混', '意呆利')]
    with open(r"d:\workBook3.csv", "w") as b:
        b_scv = csv.writer(b)   # 创建csv对象
        b_scv.writerow(headers)     # 写入一行(标题)
        b_scv.writerows(rows)       # 写入多行(数据)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    结果展示

    在这里插入图片描述

    3. os和os.path模块

    os模块 可以帮助我们直接对操作系统进行操作.
    我们可以直接调用操作系统的可执行文件、命令,直接操作文件、目录等等
    os模块 是做系统运维非常重要的基础

    os模块-调用操作系统命令

    实操代码

    # 【示例】 os.system 调用windows系统的记事本程序
    os.system("notepad.exe")
    
    # 【示例】 os.system 调用windows系统中ping命令
    # 如果出现乱码, 请看 文件操作->文件的写入->中文乱码->控制台输出时 进行配置
    os.system("ping www.baidu.com")
    
    # 【示例】运行安装好的微信
    os.startfile(r"C:\Program Files (x86)\Tencent\WeChat\WeChat.exe")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    os模块-文件和目录操作

    可以通过前面讲的文件对象实现对于文件内容的读写操作.
    如果还需要对文件和目录做其他操作,可以使用 os 和 os.path 模块.

    • os 模块下常用操作文件的方法
      在这里插入图片描述
    • os 模块下关于目录操作的相关方法
      在这里插入图片描述

    实操代码

    import os
    # 【示例】 os 模块:创建、删除目录、获取文件信息等
    print("系统名称:", os.name)  # windows-->nt linux-->posix
    print("当前操作系统所使用的路径分隔符:", os.sep)  # windows-->\  linux-->/
    print("行间隔符:", repr(os.linesep))  # windows-->\r\n linux-->\n
    print("当前目录:", os.curdir)
    
    a = "3"
    print(a)
    # 返回对象的规范字符串表示
    print(repr(a))
    # 获取文件和文件夹的相关信息
    print(os.stat("MyPy08-FileRead.py"))
    
    # 工作目录的操作
    print(os.getcwd())  # 获取当前工作目录
    os.chdir("D:")  # 切换当前工作目录
    os.mkdir("学习资料大全")  # 创建目录
    os.rmdir("学习资料大全")  # 删除目录
    # os.makedirs("人种/黄种人/中国人")  # 创建多级目录, 调用成功一次之后, 再次调用会报错
    # os.rename("人种", "亚洲人")     # 此方法也只能调用一次
    print(os.listdir("亚洲人"))  # 当前目录下的子目录
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    注意事项
    在调用 os.rename() 时, 如果出现报错 PermissionError: [WinError 5] 拒绝访问,
    则需要你在需要重命名的文件夹上面配置用户的权限. 修改之后便可进行重命名. 如下图所示

    在这里插入图片描述
    在这里插入图片描述

    os.path模块

    os.path 模块提供了目录相关(路径判断、路径切分、路径连接、文件夹遍历)的操作

    在这里插入图片描述
    实操代码

    # 【示例】测试 os.path 中常用方法
    print("是否是绝对路径:", os.path.isabs("d:/a.txt"))
    print("是否是目录: ", os.path.isdir(r"d:\a.txt"))
    print("文件是否存在: ", os.path.exists("a.txt"))
    print("文件大小: ", os.path.getsize("a.txt"))
    print("输出绝对路径:", os.path.abspath("a.txt"))
    print("输出所在目录:", os.path.dirname("d:/a.txt"))
    # 获得创建时间、访问时间、最后修改时间
    print("输出创建时间:", os.path.getctime("a.txt"))
    print("输出最后访问时间:", os.path.getatime("a.txt"))
    print("输出最后修改时间", os.path.getmtime("a.txt"))
    # 对路径进行分割、连接操作
    path = os.path.abspath("a.txt")  # 返回绝对路径
    print("返回元组:目录、文件:", os.path.split(path))
    print("返回元组:路径、扩展名", os.path.splitext(path))
    print("返回路径:aa\bb\cc", os.path.join("aa", "bb", "cc"))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    列出指定目录下所有的 .py 文件,并输出文件名

    # 列出指定目录下所有的 .py 文件,并输出文件名
    import os
    
    path = os.getcwd()
    file_list = os.listdir(path)
    
    for filename in file_list:
        pos = filename.rfind(".")
        if filename[pos + 1:] == "py":
            print(filename, end="\t")
    print()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    walk()递归遍历所有文件和目录

    os.walk() 方法是一个简单易用的文件、目录遍历器,可以帮助我们高效的处理文件、目录方面的事情

    格式如下: os.walk(top[, topdown=True[, onerror=None[, followlinks=False]]])

    • top :是要遍历的目录。 topdown :可选, True ,先遍历 top 目录再遍历子目录
    • 返回三元组( root 、 dirs 、 files ):
      root :当前正在遍历的文件夹本身
      dirs :一个列表,该文件夹中所有的目录的名字
      files :一个列表,该文件夹中所有的文件的名字

    实操代码

    # 【示例】使用 walk() 递归遍历所有文件和目录
    path = os.getcwd()[:os.getcwd().rfind("\\")]	# 获取上级路径, 作用是能够输出更多的文件
    file_list = os.walk(path, topdown=False)
    
    for root, dirs, files in file_list:
        for name in files:
            print(os.path.join(root, name))
        for name in dirs:
            print(os.path.join(root, name))  # 用于拼接目录
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    输出结果
    在这里插入图片描述

    递归遍历目录下所有文件

    实操代码

    # 【示例】使用递归算法遍历目录下所有文件
    def my_print_file(path, level):
        child_files = os.listdir(path)
        for file in child_files:
            file_path = os.path.join(path, file)
            print("\t" * level + file_path[file_path.rfind(os.sep)+1:])
            if os.path.isdir(file_path):
                my_print_file(file_path, level + 1)
    
    
    my_print_file(path, 0)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    4. shutil模块(拷贝和压缩)

    shutil 模块是python标准库中提供的,主要用来做文件和文件夹的拷贝、移动、删除等;
    还可以做文件和文件夹的压缩、解压缩操作. os 模块提供了对目录或文件的一般操作.
    shutil 模块作为补充,提供了移动、复制、压缩、解压等操作,这些 os 模块都没有提供

    实操代码-拷贝

    import shutil
    # 【示例】实现文件的拷贝
    os.chdir("D:")  # 切换当前工作目录
    shutil.copyfile("a.txt", "a_copy.txt")
    
    # 【示例】实现递归的拷贝文件夹内容(使用 shutil 模块)
    shutil.copytree("亚洲人/黄种人", "人种", ignore=shutil.ignore_patterns("*.html", "*htm"))  # "音乐"文件夹不存在才能用
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    实操代码-压缩与解压

    # 【示例】实现将文件夹所有内容压缩(使用 shutil 模块)
    # 将"亚洲人/黄种人"文件夹下所有内容压缩到"生物资料"文件夹下生成race.zip
    shutil.make_archive("生物资料/race", "zip", "亚洲人/黄种人")
    
    # 压缩:将指定的多个文件压缩到一个zip文件
    z = zipfile.ZipFile("a.zip", "w")
    z.write("a.txt")
    z.write("b.txt")
    z.close()
    
    # 【示例】实现将压缩包解压缩到指定文件夹(使用 shutil 模块)
    z2 = zipfile.ZipFile("a.zip", "r")
    z2.extractall("d:/生物资料")
    z2.close()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

  • 相关阅读:
    2024/4/16 网络编程day4
    商品分类,汉码批发进销存管理软件
    Android学习笔记 64. ConstraintLayout使用布局编辑器
    VR-Platform 国产神器
    HTTP协议详解
    编写Android可执行二进制文件调用so
    kubelet源码分析 添加 pod
    什么是正直型人格?正直型性格的优劣势及职业分析
    fopen/fwrite/fread 对UNICODE字符写入的总结
    前端开发:Vue混入(mixin)的使用
  • 原文地址:https://blog.csdn.net/qq_43371556/article/details/124942659