《接口自动化测试框架》代码片段 - 文件和目录操作封装

抛砖引玉

在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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

需要休息的KK.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值