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()

结果展示

在这里插入图片描述

中文乱码

代码编写时

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()

控制台输出时

问题描述

我们一般习惯把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()

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()

with语句(上下文管理器)

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

实操代码

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

3. 文件的读取

文件读取的步骤:

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

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

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

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

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

代码格式

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

注意:

  • 在读取文件时, 需要注意读写时字符编码的一致性, 如果写的时候没有指定编码(默认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)

二进制文件的读取和写入

二进制文件的处理流程和文本文件流程一致。首先还是要创建文件对象,
创建好二进制文件对象后,仍然可以使用 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)

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. 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)

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)

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

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)       # 写入多行(数据)

结果展示

在这里插入图片描述

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")

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("亚洲人"))  # 当前目录下的子目录

注意事项
在调用 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"))

列出指定目录下所有的 .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()

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))  # 用于拼接目录

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

递归遍历目录下所有文件

实操代码

# 【示例】使用递归算法遍历目录下所有文件
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)

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"))  # "音乐"文件夹不存在才能用


实操代码-压缩与解压

# 【示例】实现将文件夹所有内容压缩(使用 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()

猜你喜欢

转载自blog.csdn.net/qq_43371556/article/details/124942659