Python学习笔记 | 办公自动化基础之文件和文件夹操作
利用python实现办公自动化的基础就是管理磁盘文件和文件夹,如文件和文件夹的新建、删除、遍历查找等等,使用到的模块有os、shutil、golb、pathlib等。内容虽然简单,但是有些关键点也很容易出错,在这里做一下记录。
一、os模块
系统os模块提供了访问操作系统底层的接口,通过模块众多的方法可以实现对文件和文件夹的基础管理。os模块的方法如下:(前面有★符号的表示是经常使用的方法)
方法名 | 作 用 |
★os.listdir | 列出指定目录下的所有子目录和文件(不向下遍历) |
★os.scandir | 扫描指定目录下的所有子目录和文件(不向下遍历) |
★os.walk | 生成目录树下的所有文件名(遍历所有目录) |
★os.getcwd | 获取当前工作目录 |
★os.chdir | 改变目录(切换路径) |
os.mkdir/makedirs | 创建目录/创建多层目录(如:一次性创建a\b\c\d) |
os.rmdir/removedirs | 删除目录/删除多层目录 |
os.remove | 删除文件 |
os.rename | 重命名文件 |
★os.path.abspath | 获取当前目录的绝对路径 |
★os.path.basename | 获取指定路径中的基本名称(去掉路径) |
★os.path.dirname | 获取指定路径中的基本路径(去掉文件名) |
★os.path.join | 将给定的几个基本路径组合成一个路径 |
★os.path.split | 将路径分割成路径和文件名两部分(dirname,basename) |
os.path.splitext | 将路径分割成路径+文件名(不含扩展名)和扩展名两部分 |
os.path.getatime os.path.getctime os.path.getmtime | 获取文件或目录的最近访问、创建和修改时间,返回值是时间戳 |
os.path.getsize | 获取文件尺寸 |
★os.path.exists | 判断路径是否存在 |
os.path.isabs | 判断是否为绝对路径 |
★os.path.isdir | 判断是否为目录 |
★os.path.isfile | 判断是否为文件 |
下面针对os模块的几个重要方法进行基本讲解:
1、os.listdir方法
os.listdir方法没有多余参数和属性,把子目录名称和文件名称统一放到一个列表里(目录和文件名称里均不含路径信息),使用时需要自行判断列表元素是目录还是文件。os.listdir方法比较简单直接,但是用起来比较顺手。演示代码如下:
import os
# 列出当前目录下的所有子目录和文件
result = os.listdir('./')
# 查看listdir方法的返回值类型
print('返回值类型:', type(result))
# 查看返回结果
for item in result:
if os.path.isdir(item):
print(item, '目录')
else:
print(item, '文件')
输出结果:
返回值类型: <class 'list'>
test 目录
test.py 文件
搜索文件和文件夹.py 文件
递归遍历目录.py 文件
2、os.scandir方法
os.scandir是Python官方推荐的方法,返回值是一个迭代器,里面的元素是os.DirEntry对象,该对象有两个属性:path和name,path属性中包含路径信息,name属性中不包含路径路径信息。演示代码如下:
import os
# 扫描当前目录下的所有子目录和文件
result = os.scandir('./')
# 查看scandir的返回值类型,结果是迭代器
print(type(result))
# 使用循环遍历输出scandir的结果,有两个属性:path和name
# path属性中包含路径,name属性中不包含路径,只有目录或文件名
for item in result:
print(item.path, '\t', item.name)
输出结果:
<class 'nt.ScandirIterator'>
./test test
./test.py test.py
./搜索文件和文件夹.py 搜索文件和文件夹.py
./递归遍历目录.py 递归遍历目录.py
3、os.walk方法
os.walk方法自动遍历指定目录,包括遍历每层的子目录,返回值是一个生成器。它有四个参数:
- top:指定的顶层目录
- topdown:可选,为True时,则自上而下,而为False时,则自下而上
- onerror:可选,是一个函数,OSError实例
- followlinks:可选,通过软链接访问目录
演示代码如下:
import os
# 遍历指定目录
result = os.walk('./')
# 查看返回类型是生成器
print('返回值类型:', type(result))
# 遍历输出
for item in result:
print('当前目录:', item[0])
print('包含目录:', end='')
for i in item[1]:
print(i, end=',')
print()
print('包含文件:', end='')
for j in item[2]:
print(j, end=',')
print()
输出结果:
返回值类型: <class 'generator'>
当前目录: ./
包含目录:test,
包含文件:test.py,搜索文件和文件夹.py,递归遍历目录.py,
当前目录: ./test
包含目录:
包含文件:
4、os.path.abspath和os.path.join方法
os.path.abspath方法是获取当前目录的绝对路径,os.path.join方法用来将几个子目录名连接成一个完整路径。为什么要将这两个方法放在一起说呢?因为我在分析和学习pygame包自带的一个游戏代码时,发现了官方写代码的方式,全都是考虑了跨平台运行问题。
首先,官方程序的第一行就是#!/usr/bin/env python,这行代码在windows操作系统里运行时会当成注释忽略,而在linux系统里是指定解释器位置,避免程序拿到linux系统运行时出错,这就是考虑了跨平台问题。
然后,再说这两个方法。如果我们在写代码时把路径写成了windows系统的绝对路径,如:d:\python练习\飞机大战,那么你的程序拿到linux系统下是一定运行不起来的,没处去找这个路径,linux系统干脆就不分CDE盘。这时就可以使用这两个方法来解决路径跨平台问题,演示代码如下:
import os
main_dir = os.path.split(os.path.abspath(__file__))[0]
file = os.path.join(main_dir, "data", 'play.py')
print(file)
输出结果:
D:\python练习\办公自动化\data\play.py
代码分析:首先获取当前文件所在位置的绝对路径,__file__表示当前文件,通过切割路径得到主路径;然后使用os.path.join方法,将主路径、子目录和文件名连接成最后想要的完整路径。这些代码里面没有出现任何操作系统的路径格式,这样os.path.abspath方法得到就是当前系统系统的路径格式,join方法同样按照当前操作系统规则进行连接,所以确保跨平台不会出现路径出错问题。
5、其它常用方法
演示代码如下:
import os
print(os.path.basename(r'd:\python练习\飞机大战\plane_main.py'))
输出结果:
plane_main.py
print(os.path.dirname(r'd:\python练习\飞机大战\plane_main.py'))
输出结果:
d:\python练习\飞机大战
print(os.path.join(os.getcwd(), 'test'))
输出结果:
D:\python练习\办公自动化\test
path1 = os.path.split(r'd:\python练习\飞机大战\plane_main.py')
print(path1[0], '\t', path1[1])
输出结果:
d:\python练习\飞机大战 plane_main.py
path2 = os.path.splitext(r'd:\python练习\飞机大战\plane_main.py')
print(path2[0], '\t', path2[1])
输出结果:
d:\python练习\飞机大战\plane_main .py
6、综合实例
下面用一个综合实例来演示os模块的主要方法的使用,这个程序不使用os提供的现成遍历函数walk,而是自己编写递归函数,来遍历获取指定目录下的所有文件,旨在深刻理解os模块各个方法的使用。
难点:递归函数从底层目录返回上级目录时,路径非常容易出错,造成返回结果不正常。
解决办法:在每层目录获取到包含的子目录列表时,直接把子目录转换成绝对路径形式再追加到目录列表里。这样在遍历完底层目录返回后,重新获得的路径是绝对路径,确保不出问题。
代码如下:
import os
# 递归函数
def get_allfile(path):
# 定义全局变量
global all_list
# 创建用于包含子目录的列表,初始值为空
all_dirs = []
all_files = []
# 切换到指定目录,这是向出口靠近的条件
os.chdir(path)
# 遍历指定目录本层的所有子目录和文件
for file in os.listdir(path):
if os.path.isfile(file):
# 如果是文件就直接追加到当前文件列表中
all_files.append(file)
else:
# 关键:如果是目录,则把该子目录的绝对路径追加到子目录列表中,防止递归往回返时路径出错
all_dirs.append(os.path.abspath(file))
# 将当前层目录名、包含的所有子目录和文件以元组形式追加到公共变量all_list列表中
all_list.append((path, all_dirs, all_files))
# 如果子目录列表不是空的,说明里面还有子目录,则调用本身继续遍历子目录,否则返回。
if len(all_dirs):
for file in all_dirs:
# 调用本身,参数是子目录名
get_allfile(file)
else:
# 如果不包含子目录,则返回,这是递归函数的出口。
return
return all_list
# 定义一个所有文件的空列表,在递归函数里向该列表里追加遍历到的文件名
all_list = []
# 调用递归函数遍历指定目录
result = get_allfile(r'd:\python练习\飞机大战')
# 循环遍历返回值列表,每个列表元素都是一个三元组
for top_dir, subdir, file in result:
print('当前目录:', top_dir)
print('包含目录:')
for i in subdir:
print(i, '\t')
print()
print('包含文件:')
for j in file:
print(j, '\t')
print()
输出结果:(未列出全部输出结果)
当前目录: d:\python练习\飞机大战
包含目录:
d:\python练习\飞机大战\build
d:\python练习\飞机大战\dist
d:\python练习\飞机大战\images
d:\python练习\飞机大战\sound
d:\python练习\飞机大战\__pycache__
包含文件:
plane_main.exe
plane_main.py
plane_main.spec
plane_sprites.py
score
test.py
飞机大战.py
飞机大战V2.py
飞机大战V3.py
飞机大战V4.py
二、glob模块
glob模块非常简单,用来查找符合特定规则的目录和文件,返回值是一个列表,主要用作补充和辅助os模块。该模块最大的特点就是支持通配符,因此在查找时就显得非常灵活。
1、通配符
- *:匹配0个或多个字符
- **:匹配所有文件、目录、子目录和子目录里的文件
- ?:匹配一个字符
- []:匹配指定范围内的字符,如[0-9]匹配数字,[a-z]匹配小写字母
2、三个方法
- glob.glob方法:返回符合匹配条件的所有文件的路径,参数recursive表示递归调用,与特殊通配符“**”一同使用,返回值是列表。
- glob.iglob方法:跟glob.glob方法一样,返回值是迭代器。
- glob.escape方法:忽略所有特殊字符的通配符含义
glob模块演示代码如下:
import glob
# 输出指定目录下的所有py文件
print(glob.glob(r'd:\python练习\飞机大战\*.py'))
输出结果:['d:\\python练习\\飞机大战\\plane_main.py', 'd:\\python练习\\飞机大战\\plane_sprites.py', 'd:\\python练习\\飞机大战\\test.py']
# 输出所有t开头的py文件
print(glob.glob(r'd:\python练习\飞机大战\t*.py'))
输出结果:['d:\\python练习\\飞机大战\\test.py']
# 输出当前文件夹下文件名由一个字母构成的py文件
print(glob.glob('./?.py'))
输出结果:['.\\t.py']
# 输出所有文件名后面是数字1的py文件
print(glob.glob('./*[1].py'))
输出结果:['.\\t1.p
# 输出当前文件夹下的所有目录和文件,不向下遍历
print(glob.glob('./**'))
输出结果:['.\\t.py', '.\\t1.py', '.\\test', '.\\test.py', '.\\搜索文件和文件夹.py', '.\\递归遍历目录.py']
# 输出当前文件夹下的所有目录和文件,并遍历所有子文件夹
print(glob.glob('./**',recursive=True))
输出结果:['.\\', '.\\t.py', '.\\t1.py', '.\\test', '.\\test\\find_file.py', '.\\test.py', '.\\搜索文件和文件夹.py', '.\\递归遍历目录.py']
三、shutil模块
shutil是shell until的缩写,同样是作为os模块的补充,提供了复制、移动、删除、压缩、解压等操作。但是,shutil 模块对压缩包的处理是调用 ZipFile 和 TarFile这两个模块来进行的,跟zipfile模块的压缩解压缩是不同的。
常用方法:
- shutil.copy:复制文件
- shutil.copytree:复制文件夹
- shutil.move:移动文件或文件夹
- shutil.rmtree:删除文件夹
- zipobj.write:创建一个压缩包
- zipobj.namelist:读取压缩包中的文件信息
- zipobj.extract:解压缩单个文件
- zipobj.extractall:解压缩所有文件
shutil模块使用简单,不再赘述。
四、pathlib模块
pathlib是从python3开始推出的跟os模块功能重叠的内置模块,能够完全替代os.path。Python官网中这样说:“对于字符串的低级路径操作,也可以使用该os.path模块”,这足以证明pathlib有着os.path不能比拟的优点。
在Python 3.4之后,pathlib成为标准库模块,其使用面向对象的编程方式来表示文件系统路径,丰富了路径处理的方法。
1、pathlib模块的优势
- pathlib实现统一管理,解决了传统操作导入模块不统一问题;
- pathlib使得在不同操作系统之间切换非常简单;
- pathlib是面向对象的,路径处理更灵活方便,解决了传统路径和字符串并不等价的问题;
- pathlib简化了很多操作,简单易用。
2、pathlib模块的主要属性和方法
pathlib模块有一个重要的类——Path,基本上对文件和文件夹的所有操作都是使用Paht的方法和属性完成的,因此重点介绍Paht类的属性和方法的使用。
属性 | 作 用 |
Path.name | 返回完整文件名(包含后缀),如果是目录则返回目录名 |
Path.stem | 返回文件名(不包含后缀),如果是目录则返回目录名 |
Path.suffix | 返回文件后缀 |
Path.parents | 返回所有上级目录的列表 |
Path.parts | 返回分割路径后的元组 |
Path.root | 返回路径的根目录 |
Path.driver | 返回驱动器名称 |
方法 | 作 用 |
Path.resolve() | 获得绝对路径 |
Path.cwd() | 获得当前工作目录 |
Path.home() | 返回电脑的用户目录 |
Path.stat() | 获得文件属性 |
Path.chmod() | 修改文件权限和时间戳 |
Path.mkdir() | 创建目录 |
Path.rmdir() | 删除目录 |
Path.unlink() | 删除一个文件 |
Path.rename() | 文件或文件夹重命名,如果路径不同,会移动并重新命名 |
Path.replace() | 文件或文件夹替换,如果路径不同,会移动并重新命名,如果存在,则破坏现有目标。 |
Path.open() | 打开文件(支持with) |
Path.read_bytes() | 以字节格式读取文件 |
Path.read_text() | 以文本格式读取文件 |
Path.write_bytes() | 以字节格式写入文件 |
Path.write_text() | 以文本格式写入文件 |
Path.iterdir() | 查找所有子目录和文件,不递归遍历子目录,没有参数 |
Path.glob() | 查找所有文件,不递归遍历子目录,必须指定参数 |
Path.rglob() | 递归遍历目录下的所有子目录和文件,必须指定参数 |
Path.joinpath() | 拼接路径 |
Path.exists() | 判断文件或目录是否存在 |
Path.is_dir() | 判断是否为目录 |
Path.is_file() | 判断是否为文件 |
Path.is_symlink() | 判断是否为符号链接 |
3、代码演示
from pathlib import Path
# 创建pathlib模块Path类对象
path=Path(r'd:\python练习\飞机大战')
print(path.cwd()) # 输出当前目录
print(path.home()) # 输出电脑的用户目录
输出结果:
D:\python练习\办公自动化
C:\Users\Administrator.User-2022BIVGGU
# 使用Path类拼接路径
path1=Path(path.cwd(),'test')
path2=Path.joinpath(path.cwd(),'test')
print(path1)
print(path2)
输出结果:
D:\python练习\办公自动化\test
D:\python练习\办公自动化\test
path=Path.cwd()
print(path.name) # 输出当前路径对象的目录名
print(path.stem) # 输出当前路径对象的目录名
print(Path(r'd:\python练习\飞机大战').name) # 输出指定目录的当前目录名
输出结果:
办公自动化
办公自动化
飞机大战
# 查找当前目录下的所有py文件,不递归遍历子目录
resulte = path.glob('*.py') # 必须指定参数
for item in resulte:
# 分别输出完整文件名,文件名和后缀
print(item.name, item.stem, item.suffix, sep=' | ')
输出结果:
t.py | t | .py
t1.py | t1 | .py
test.py | test | .py
搜索文件和文件夹.py | 搜索文件和文件夹 | .py
递归遍历目录.py | 递归遍历目录 | .py
# 遍历当前目录下的所有子目录和文件,不递归遍历子目录
resulte = path.iterdir() # 不能带参数
for item in resulte:
# 分别输出完整文件名,文件名和后缀
print(item.name, item.stem, item.suffix, sep=' | ')
输出结果:
t.py | t | .py
t1.py | t1 | .py
test | test |
test.py | test | .py
搜索文件和文件夹.py | 搜索文件和文件夹 | .py
递归遍历目录.py | 递归遍历目录 | .py
# 遍历当前目录下的所有子目录和文件
resulte = path.rglob('*') # 必须指定参数
for item in resulte:
# 如果是目录,则输出该目录的绝对路径、子目录名和“子目录”三个文字
if item.is_dir():
print(item.resolve(), item.name, '子目录', sep=' | ')
# 如果是文件,则输出该文件所在目录的绝对路径、文件名和“文件”两个文字
elif item.is_file():
print(item.resolve(), item.name, '文件', sep=' | ')
输出结果:
D:\python练习\办公自动化\t.py | t.py | 文件
D:\python练习\办公自动化\t1.py | t1.py | 文件
D:\python练习\办公自动化\test | test | 子目录
D:\python练习\办公自动化\test.py | test.py | 文件
D:\python练习\办公自动化\搜索文件和文件夹.py | 搜索文件和文件夹.py | 文件
D:\python练习\办公自动化\递归遍历目录.py | 递归遍历目录.py | 文件
D:\python练习\办公自动化\test\find_file.py | find_file.py | 文件
综合实例代码:在输入的路径里查找包含输入的关键字的所有目录和文件
from pathlib import Path
# 循环检测输入的路径是否为正确格式并且路径存在
while True:
top_path = input('请输入搜索起始路径:')
# 创建pathlib模块的Path类对象,参数中将搜索路径去掉首尾空格
top_path = Path(top_path.strip())
# 如果输入路径格式正确并且该路径存在,则中断循环并向下指向
if top_path.exists() and top_path.is_dir():
break
else:
print('输入的路径有误,请重新输入!')
search = input('请输入搜索关键字:')
result = list(top_path.rglob(f'*{search}*'))
if result:
result_dir = []
result_file = []
for i in result:
if i.is_dir():
result_dir.append(i)
if i.is_file():
result_file.append(i)
if result_dir:
print(f'找到了跟“{search}”相符合的文件夹:')
for i in result_dir:
print(i)
print('-'*30)
if result_file:
print(f'找到了跟“{search}”相符合的文件:')
for i in result_file:
print(i)
else:
print(f'抱歉!在路径“{top_path}”里,没有搜索到跟“{search}"符合的文件和文件夹!')
输出结果:
请输入搜索起始路径:d:\python练习\办公自动化
请输入搜索关键字:t
找到了跟“t”相符合的文件夹:
d:\python练习\办公自动化\test
------------------------------
找到了跟“t”相符合的文件:
d:\python练习\办公自动化\t.py
d:\python练习\办公自动化\t1.py
d:\python练习\办公自动化\test.py
五、tempfile模块
tempfile模块的功能是创建临时文件和临时文件夹,程序运行结束后,创建的临时文件和文件夹会自动删除,方便临时转储文件和记录信息。
1、tempfile模块的应用场景
在大型数据处理项目中,有的处理结果是不需要向用户最终展示的,但是它们的应用又是贯穿项目始终的,在这种情况下,我们就需要使用tempfile模块来解决这种问题。
2、tempfile模块的类
tempfile模块供了四个高级类(自动清除关闭的文件)和两个需要手动清理的方法:
- TemporaryFile类:用于读写临时文件,并且保证临时文件的隐藏性,默认的文件打开模式是w+b。
- NamedTemporaryFile类:与Temporaryfile类操作类似,但是增加了对文件关闭后是否删除的判断,即delete参数,默认是True。
- TemporaryDirectory类:安全地创建一个临时目录,返回的对象可用于上下文管理器使用。
- SpooledTemporaryFile类:在Temporaryfile类基础上增加一个写入闸值Max_size,当数据没有达到max_size时,会暂存在内存中;当数据超过max_size设置的值后,数据会自动写入到临时文件里保存,默认Max_size为0。
3、tempfile模块的方法
- gettempdir():以文本格式返回系统临时文件夹名
- gettempdirb():以二进制格式返回系统临时文件夹名
- gettempprefix():以文本格式返回临时文件名
- gettempprefixb():以二进制格式返回临时文件名
- mkstemp() 和 mkdtemp() :底层临时文件和文件夹创建,需要手动清理的方法
4、演示代码
import tempfile
# 输出系统的临时文件夹路径
print('系统的临时文件夹路径是:', tempfile.gettempdir())
# 在当前文件夹里创建临时文件夹
tempdir = tempfile.TemporaryDirectory(dir='./')
print('新建的临时文件夹路径是:', tempdir.name)
# 清除临时文件夹
tempdir.cleanup()
# 使用上下文方式管理临时文件夹,不用调用cleanup方法手动清除
with tempfile.TemporaryDirectory(dir='./') as temp_dir:
# 使用上下文with模式在新建的临时文件夹中新建临时文件
with tempfile.TemporaryFile() as temp_file:
# 写入到临时文件中的信息必须是字节格式
temp_file.write(b'hello world!')
# 将指针移动到开始处读取临时文件内容并解码输出
temp_file.seek(0)
msg = temp_file.read()
print(msg.decode())
输出结果:
系统的临时文件夹路径是: C:\Users\ADMINI~1.USE\AppData\Local\Temp
新建的临时文件夹路径是: ./tmph5rj1at5
hello world!
六、zipfile模块
zipfile是压缩和解压缩模块,虽然叫zipfile,但是除了zip之外,rar,war,jar这些压缩(或者打包)文件格式也都可以处理。
1、常用方法
- ZipFile.getinfo:获取zip文档内指定文件的信息
- ZipFile.infolist:获取zip文档内所有文件的信息
- ZipFile.namelist:获取zip文档内所有文件的名称列表。
- ZipFile.extractall:将zip文档内的指定文件解压到当前目录,参数:member 要解压的文件名称,path解析文件保存的文件夹,pwd 解压密码
- ZipFile.printdir:将zip文档内的信息打印到控制台上
- ZipFile.setpassword:设置zip文档的密码
- ZipFile.read:获取zip文档内指定文件的二进制数据
- ZipFile.write:将指定文件添加到zip文档中
- ZipFile.writestr:支持将二进制数据直接写入到压缩文档
2、演示代码
import zipfile
from pathlib import Path
# 创建路径对象
path=Path('./')
# 获取当前文件夹下的所有py文件
files=path.glob('*.py')
# 创建并打开zippy.zip压缩文件
with zipfile.ZipFile('zippy.zip','w') as zipobj:
# 循环将所有py文件添加到压缩文件中
for file in files:
zipobj.write(file)
print(f'文件{file}被添加到zippy.zip压缩文件中...')
# 给压缩文件设置密码
zipobj.setpassword(b"123")
print('压缩完毕!')
输出结果:
文件t.py被添加到zippy.zip压缩文件中...
文件t1.py被添加到zippy.zip压缩文件中...
文件test.py被添加到zippy.zip压缩文件中...
文件搜索文件和文件夹.py被添加到zippy.zip压缩文件中...
文件递归遍历目录.py被添加到zippy.zip压缩文件中...
压缩完毕!
注:经过测试,添加的密码不起作用,需要深入研究。