Python系列文章目录
第一章 Python 入门 第二章 Python基本概念 第三章 序列 第四章 控制语句 第五章 函数 第六章 面向对象基础 第七章 面向对象深入 第八章 异常机制 第九章 文件操作
前言
在本章节, 主要介绍了文件操作相关的API方法使用 首先我们将会学习什么是文件操作, 以及文件分类还有在IO操作时会用到的常用编码介绍 然后我们学习了文件操作的流程, 创建->写入->关闭 在然后我们学习了文件的拓展, 序列化模块pickle, 文件操作模块csv, 系统操作调用模块os和os.path以及文件拷贝压缩模块shutil
一、什么是文件操作
一个完整的程序一般都包括数据的存储和读取;我们在前面写的程序数据都没有进行实际的存储,因此python解释器执行完数据就消失了 实际开发中,我们经常需要从外部存储介质(硬盘、光盘、U盘等)读取数据,或者将程序产生的数据存储到文件中,实现“持久化”保存
1. 文件分类
按文件中数据组织形式,我们把文件分为文本文件和二进制文件两大类:
-
文本文件 文本文件存储的是普通“字符”文本,python默认为 unicode 字符集,可以使用记事本程序打开 -
二进制文件 二进制文件把数据内容用“字节”进行存储,无法用记事本打开, 必须使用专用的软件解码. 常见的有: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
f.writelines(s)
f.close()
close()关闭文件流
由于文件底层是由操作系统控制,所以我们打开的文件对象必须显式调用 close() 方法关闭文件对象. 当调用 close() 方法时,首先会把缓冲区数据写入文件(也可以直接调用 flush() 方法),再关闭文件,释放文件对象
注意:
close() 一般结合异常机制的 finally 一起使用- 也可以通过 with 关键字实现无论何种情况都能关闭打开的文件对象(推荐)
实操代码
try:
f = open(r"d:\c.txt", "a")
s = "来自深渊"
f.write(s)
except BaseException as e:
print(e)
finally:
f.close()
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
实操代码
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:
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') 可读的二进制文件对象
实操代码
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("=================文件任意位置操作======================")
with open(r"d:\cc.txt", "r") as f:
print("文件名是{0}".format(f.name))
print(f.tell())
print("读取文件的内容", str(f.readline()))
print(f.tell())
f.seek(4, 0)
print("文件读取的内容", str(f.readline()))
print(f.tell())
三、文件操作拓展模块
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)
headers = next(o_csv)
print(headers)
for row in o_csv:
print(row)
结果展示
csv文件写入
实操代码
headers = ['姓名', '年龄', '工作', '住址']
rows = [('JOJO', '18', '按摩师', '英国'), ('迪奥', '19', '老板', '埃及'), ('乔鲁诺乔巴纳', '20', '混混', '意呆利')]
with open(r"d:\workBook3.csv", "w") as b:
b_scv = csv.writer(b)
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
print("系统名称:", os.name)
print("当前操作系统所使用的路径分隔符:", os.sep)
print("行间隔符:", repr(os.linesep))
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("学习资料大全")
print(os.listdir("亚洲人"))
注意事项 在调用 os.rename() 时, 如果出现报错 PermissionError: [WinError 5] 拒绝访问 , 则需要你在需要重命名的文件夹上面配置用户的权限. 修改之后便可进行重命名. 如下图所示
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 文件,并输出文件名
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 :一个列表,该文件夹中所有的文件的名字
实操代码
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.copytree("亚洲人/黄种人", "人种", ignore=shutil.ignore_patterns("*.html", "*htm"))
实操代码-压缩与解压
shutil.make_archive("生物资料/race", "zip", "亚洲人/黄种人")
z = zipfile.ZipFile("a.zip", "w")
z.write("a.txt")
z.write("b.txt")
z.close()
z2 = zipfile.ZipFile("a.zip", "r")
z2.extractall("d:/生物资料")
z2.close()
|