抛砖引玉
在Python中,文件和目录的操作是一项基础且频繁的任务。
Python提供了一系列强大的内置函数和模块,使得这些操作变得既简单又高效。
这些工具极大地简化了对文件和目录的各种操作,从创建新文件、读取数据、写入内容,到删除旧文件、管理目录结构,都变得轻而易举。
在之前的文章中已经对这部分内容做了详细的介绍,本次意在抛砖引玉,不在****重复自我。
本次将为大家展示一个实用的工具类,这个工具类是《接口自动化框架(付费)》中的一部分,专门用于封装文件和目录操作的相关功能。
通过这个工具类,你可以更加高效地管理测试数据、读取配置文件以及执行其他与文件和目录相关的操作。希望这个工具类能够对你的工作有所帮助。
历史文章:Python 3 OS标准库学习笔记速查表
历史文章:Python 3 Shutil标准库学习笔记速查表
历史文章:Python 3 Pathlib标准库学习笔记速查表
框架文章:完美落地的自动化测试框架:智能生成?业务依赖?动态替换?报告构建?你来,这儿有!
注意:框架暂不开源,66R包执行,可免费讲解。
文件操作
1.打开文件
Python中的
open()
函数是文件操作的起点。它接受三个主要参数:文件名称、模式、和编码。
文件名称是你要操作的文件的字符串路径;
模式则决定了如何打开文件。常见的模式有:
'r'
:只读模式,文件必须存在。'w'
:写入模式,如果文件存在则会被覆盖,不存在则创建新文件。'a'
:追加模式,如果文件存在,则内容会被追加到文件末尾,不存在则创建新文件。'x'
:独占模式,如果文件已存在,则操作会失败。- 此外,还有
'b'
和't'
模式,分别表示二进制和文本模式。- 通常,如果不指定模式,则默认为
't'
(文本模式)。编码则决定了以什么编码格式读取文件中的内容,默认是UTF-8;
例如:
file.txt文件内容
Hello World,Hello Python~
Hello World,Hello Python~
Hello World,Hello Python~
example01.py
with open('file.txt', 'r') as f:
content = f.read()
print(content)
# Hello World,Hello Python~
# Hello World,Hello Python~
# Hello World,Hello Python~
这里使用了 with 语句,它可以确保文件在操作完成后被正确关闭,即使在写入过程中发生异常也是如此。
2.读取文件
读取文件通常使用
read()
方法,它读取文件的全部内容并返回一个字符串。如果要按行读取,可以使用
readline()
或readlines()
方法。
例如:
with open('file.txt', 'r') as f:
content = f.readline()
print(content) # Hello World,Hello Python~
with open('file.txt', 'r') as f:
content = f.readlines()
print(content) # ['Hello World,Hello Python~\n', 'Hello World,Hello Python~\n', 'Hello World,Hello Python~']
3.写入文件
写入文件使用
write()
方法,它接受一个字符串参数,并将该字符串写入文件。
with open('file.txt', 'a') as f:
f.write('New Hello World,Hello Python~\n')
目录操作
Python的
os
模块提供了许多用于目录操作的函数。
1.创建目录
使用
os.makedirs()
函数可以创建目录。如果目录已存在,可以设置exist_ok=True
来避免引发异常。
import os
os.makedirs('测试文件夹') # 当前目录下不存在“测试文件夹”时创建,否则抛出“FileExistsError”异常
os.makedirs('测试文件夹', exist_ok=True) # 当前目录不存在则创建,否则忽略创建
2.删除目录
使用
os.rmdir()
函数可以删除空目录。如果要删除非空目录及其内容,可以使用shutil.rmtree()
函数。
import os
os.rmdir('测试文件夹') # 仅当目录为空时才有效
或者:
import shutil
shutil.rmtree('测试文件夹') # 删除目录及其内容
3.获取当前工作目录
使用os.getcwd()
函数可以获取当前Python脚本的工作目录。
import os
current_dir = os.getcwd()
print(current_dir) # /Users/xxxx/PythonWorkspace/第49课:第三方库/CASE05:OS
4.改变当前工作目录
使用
os.chdir()
函数可以改变当前工作目录。
import os
os.chdir('/path/to/directory')
5.列出目录内容
使用
os.listdir()
函数可以列出指定目录中的所有文件和子目录。
import os
contents = os.listdir('.') # 列出当前目录内容
print(contents) # ['file.txt', 'FileUtils.py', 'example01.py', '测试文件夹']
路径操作
Python的
os.path
模块提供了许多用于路径操作的函数,如拼接路径、判断路径是否存在、获取路径的各部分等。
1.路径拼接
import os
path = os.path.join('dir1', 'dir2', 'file.txt')
print(path) # dir1/dir2/file.txt
2.路径分裂
paths = os.path.split(path)
# 将路径和最后一层文件或目录分裂成元祖
print(paths) # ('dir1/dir2', 'file.txt')
3.路径判断
# 判断路径是否存在
if os.path.exists("./file.txt"):
print("路径存在") # 路径存在
else:
print("路径不存在")
# 判断路径是否为目录
if os.path.isdir("./file.txt"):
print("路径是目录")
else:
print("路径不是目录") # 路径不是目录
# 判断路径是否为文件
if os.path.isfile("./file.txt"):
print("路径是文件") # 路径是文件
else:
print("路径不是文件")
代码封装
# -*- coding: utf-8 -*-
"""
@Author : yangkai
@Email : 807440781@qq.com
@Project : KKNOBUG-API
@Module : FakeDataHook.py
@DateTime: 2024/5/11 22:29
"""
import os
import shutil
import zipfile
from datetime import datetime
class FileUtils:
"""
文件/目录操作工具类封装
1.在指定路径下创建目录(路径不存在则创建返回True,路径存在则不创建返回False)
2.在指定路径下创建文件(文件不存在则创建返回True,文件存在则不创建返回False)
3.检查指定文件路径最后修改日期时间(文件不存在则抛出异常,文件存在则返回最后修改日期时间)
4.获取指定文件大小(文件不存在则抛出异常,文件存在则返回最后修改日期时间)
5.检查指定路径是不是目录(是目录则返回True,不是目录则返回False)
6.检查指定路径是不是文件(是文件则返回True,不是文件则返回False)
7.获取指定路径下最后创建的文件名称(路径不存在或路径下没有文件抛出异常,路径存在则返回最后创建的文件名称)
8.获取指定路径下最后创建的目录名称(路径不存在或路径下没有文件抛出异常,路径存在则返回最后创建的目录名称)
9.删除指定路径的文件(路径不存在时抛出异常,删除成功时返回True)
10.删除指定路径的目录(路径不存在时抛出异常,删除成功时返回True)
11.获取指定路径下所有子文件列表(每一个子文件以完整路径返回)
12.拷贝目标路径下的所有文件或目录到指定路径下(拷贝成功返回True,失败或异常返回False)
13.将目标路径下的所有文件,压缩到指定路径的压缩文件中
"""
@staticmethod
def create_directory(path: str) -> bool:
"""
在指定路径下创建目录(路径不存在则创建返回True,路径存在则不创建返回False)
:param path: 目录路径
:return: 如果目录成功创建,则返回True;如果目录已存在,则返回False
"""
if not os.path.exists(path):
os.makedirs(path)
return True
return False
@staticmethod
def create_file(file_path: str) -> bool:
"""
在指定路径下创建文件(文件不存在则创建返回True,文件存在则不创建返回False)
:param file_path: 文件路径
:return: 如果文件成功创建,则返回True;如果文件已存在,则返回False
"""
if not os.path.exists(file_path):
with open(file_path, 'w') as file:
file.write('')
return True
return False
@staticmethod
def get_last_modified_time(file_path: str) -> datetime:
"""
检查指定文件路径最后修改日期时间(文件不存在则抛出异常,文件存在则返回最后修改日期时间)
:param file_path: 文件路径
:return: 文件的最后修改日期时间
:raise FileNotFoundError: 如果文件不存在
"""
if not os.path.exists(file_path):
raise FileNotFoundError(f"文件或目录不存在: {file_path}")
return datetime.fromtimestamp(os.path.getmtime(file_path))
@staticmethod
def get_file_size(file_path: str, unit: str = 'B') -> float:
"""
获取指定文件大小(文件不存在则抛出异常,文件存在则返回最后修改日期时间)并转换为指定单位
:param file_path: 文件路径
:param unit: 目标单位,可以是 'B' (字节), 'KB' (千字节), 'MB' (兆字节), 'GB' (吉字节) 等
:return: 文件大小(转换后的单位,保留两位小数后四舍五入,如果换算单位过大,文件过小,得出的结果或可能是0.0)
:raise FileNotFoundError: 如果文件不存在
"""
if not os.path.exists(file_path):
raise FileNotFoundError(f"文件或目录不存在: {file_path}")
file_size_bytes = os.path.getsize(file_path)
# 定义单位转换的映射
unit_mapping = {
'B': 1,
'KB': 1024,
'MB': 1024 * 1024,
'GB': 1024 * 1024 * 1024,
# 可以根据需要添加更多单位
}
if unit not in unit_mapping:
raise ValueError(f"给定换算单位无效,必须是其中之一: {', '.join(unit_mapping.keys())}")
# 转换文件大小到指定单位
file_size_unit = round(file_size_bytes / unit_mapping[unit], 2)
return file_size_unit
@staticmethod
def is_directory(path: str) -> bool:
"""
检查指定路径是不是目录(是目录则返回True,不是目录则返回False)
:param path: 路径
:return: 如果是目录则返回True,否则返回False
"""
return os.path.isdir(path)
@staticmethod
def is_file(path: str) -> bool:
"""
检查指定路径是不是文件(是文件则返回True,不是文件则返回False)
:param path: 路径
:return: 如果是文件则返回True,否则返回False
"""
return os.path.isfile(path)
@staticmethod
def get_latest_file_name(directory_path: str) -> str:
"""
获取指定路径下最后创建的文件名称(路径不存在或路径下没有文件抛出异常,路径存在则返回最后创建的文件名称)
:param directory_path: 目录路径
:return: 最后创建的文件名称
:raise FileNotFoundError: 如果路径不存在或路径下没有文件
"""
if not os.path.exists(directory_path) or not os.path.isdir(directory_path):
raise FileNotFoundError(f"目录不存在: {directory_path}")
# 获取目录中的所有文件
files = [f for f in os.listdir(directory_path) if os.path.isfile(os.path.join(directory_path, f))]
if not files:
raise FileNotFoundError(f"目录中不存在文件: {directory_path}")
# 按创建时间排序,取最后创建的文件
latest_file = max(files, key=lambda f: os.path.getctime(os.path.join(directory_path, f)))
return latest_file
@staticmethod
def get_latest_dir_name(path: str) -> str:
"""
获取指定路径下最后创建的目录名称(路径不存在或路径下没有文件抛出异常,路径存在则返回最后创建的目录名称)
:param path:
:return:
"""
latest_dir = None
latest_time = 0
# 遍历指定目录下的所有子目录
for entry in os.scandir(path):
if entry.is_dir(follow_symlinks=False):
# 获取目录的创建时间
dir_time = entry.stat().st_ctime
# 比较时间,如果当前目录创建时间晚于之前记录的,则更新记录
if dir_time > latest_time:
latest_time = dir_time
latest_dir = entry.name
return latest_dir
@staticmethod
def delete_file(path: str) -> bool:
"""
删除指定路径的文件(路径不存在时抛出异常,删除成功时返回True)
:param path:
:return:
"""
try:
# 删除文件
os.remove(path)
return True
except OSError as e:
# 如果文件不存在或无法删除,将捕获异常
raise OSError(f"文件删除时出错: {e}")
@staticmethod
def delete_directory(directory_path: str) -> bool:
"""
删除指定路径的目录(路径不存在时抛出异常,删除成功时返回True)
:param directory_path:
:return:
"""
try:
shutil.rmtree(directory_path)
return True
except NotADirectoryError as nde:
raise TypeError(f"路径必须是一个目录:{nde}")
@staticmethod
def get_all_files(file_path: str) -> list:
"""
获取指定路径下所有子文件列表(每一个子文件以完整路径返回)
:param file_path: 目录路径
:return:
"""
filename = []
# 获取所有文件下的子文件名称
for root, dirs, files in os.walk(file_path):
for _file_path in files:
path = os.path.join(root, _file_path)
filename.append(path)
return filename
@staticmethod
def copy_directory(src_path: str, dst_path: str) -> bool:
"""
拷贝目标路径下的所有文件或目录到指定路径下(拷贝成功返回True,失败或异常返回False)
@param src_path: 原目录
@param dst_path: 新目录
"""
if not os.path.exists(src_path):
return False
try:
if os.path.isdir(src_path):
shutil.copytree(src=src_path, dst=dst_path, dirs_exist_ok=True)
return True
if os.path.isfile(src_path):
shutil.copy(src=src_path, dst=dst_path)
return True
return False
except:
return False
@staticmethod
def zip_files(zip_file_name: str, zip_dir_path: str) -> str:
"""
将zip_dir_list路径下的所有文件,压缩到一个zip_file_name的压缩文件中
:param zip_file_name: 最终压缩文件名称
:param zip_dir_path:
:return:
"""
parent_name = os.path.dirname(zip_dir_path)
# 压缩文件最后需要close,为了方便我们直接用with
with zipfile.ZipFile(file=zip_file_name, mode="w", compression=zipfile.ZIP_STORED) as zip:
for root, dirs, files in os.walk(zip_dir_path):
for file in files:
# 不处理已打开的文件副本
if str(file).startswith("~$"):
continue
filepath = os.path.join(root, file)
writepath = os.path.relpath(filepath, parent_name)
zip.write(filepath, writepath)
zip.close()
return zip_file_name
if __name__ == '__main__':
# 创建目录,创建成功返回True,创建失败返回False
# print(FileUtils.create_directory("./new_directory"))
# 创建文件,创建成功返回True,创建失败返回False
# print(FileUtils.create_file("./new_directory/new_file.txt"))
# 获取文件最后修改时间,指定路径不存在则抛出异常,指定路径存在则返回最后修改日期实际
# print(FileUtils.get_last_modified_time("./new_directory/new_file.txt"))
# 获取文件大小,保留两位小数后四舍五入,如果换算单位过大,文件过小,得出的结果或可能是0.0
# print(FileUtils.get_file_size("./new_directory/new_file.txt", "KB"))
# 检查路径是否为目录,是目录返回True,不是目录返回False
# print(FileUtils.is_directory("./new_directory"))
# 检查路径是否为文件,是文件返回True,不是文件返回False
# print(FileUtils.is_file("./new_directory/new_file.txt"))
# 获取路径下最后创建的文件名称
# print(FileUtils.get_latest_file_name("/Users/yangkai/KKNOBUG-API/output/logs"))
# 获取路径下最后创建的目录名称
# print(FileUtils.get_latest_dir_name("./"))
# 删除路径下的文件或目录
# FileUtils.delete_file("./new_directory/new_file.txt")
# FileUtils.delete_directory("./new_directory")
# print(FileUtils.__doc__)
# 获取指定路径下所有的子文件
# print(FileUtils.get_all_files('/Users/yangkai/KKNOBUG-API/output/reports/html/1/test-cases'))
# 复制目录或文件
# print(FileUtils.copy_directory(src_path="/Users/yangkai/KKNOBUG-API/output/reports/html/6",
# dst_path="/Users/yangkai/KKNOBUG-API/output/reports/attachment/执行日志"))
# 压缩文件
# print(FileUtils.zip_files(zip_file_name="6666.zip", zip_dir_path="/Users/yangkai/KKNOBUG-API/output/reports/html/6"))
pass