Python+Selenium+Pytest+POM自动化测试框架封装详解

news2024/11/15 6:03:41

1、测试框架简介

1)测试框架的优点

  • 代码复用率高,如果不使用框架的话,代码会显得很冗余。
  • 可以组装日志、报告、邮件等一些高级功能。
  • 提高元素等数据的可维护性,元素发生变化时,只需要更新一下配置文件。
  • 使用更灵活的PageObject设计模式。

2)测试框架的整体目录

【注意】 init.py 文件用以标识此目录为一个python包。

2、首先时间管理

首先,因为很多的模块都会用到当前时间的时间戳,或者日期等等字符串,所以先单独把时间操作(我们需要获取的不同格式的时间信息)封装成一个模块。

然后让其他模块来调用即可。在 utils 目录新建 times.py 模块。

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
import time
import datetime
from functools import wraps


def timestamp():
    """时间戳"""
    return time.time()


def dt_strftime(fmt="%Y%m"):
    """
    datetime格式化时间
    :param fmt "%Y%m%d %H%M%S
    """
    return datetime.datetime.now().strftime(fmt)


def sleep(seconds=1.0):
    """
    睡眠时间
    """
    time.sleep(seconds)


def running_time(func):
    """函数运行时间"""

    @wraps(func)
    def wrapper(*args, **kwargs):
        start = timestamp()
        res = func(*args, **kwargs)
        print("校验元素done!用时%.3f秒!" % (timestamp() - start))
        return res

    return wrapper


if __name__ == '__main__':
    print(dt_strftime("%Y%m%d%H%M%S"))

3、添加配置文件

1)conf.py

UI自动化测试框架中应该有一个文件对整体的目录进行管理;

在项目中的 config 目录创建 conf.py 文件,所有的目录配置信息写在这个文件里面。

import os
from selenium.webdriver.common.by import By
from utils.times import dt_strftime


class ConfigManager(object):
    # 项目目录
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

    # 页面元素目录
    ELEMENT_PATH = os.path.join(BASE_DIR, 'page_element')

    # 报告文件
    REPORT_FILE = os.path.join(BASE_DIR, 'report.html')

    # 元素定位的类型
    LOCATE_MODE = {
        'css': By.CSS_SELECTOR,
        'xpath': By.XPATH,
        'name': By.NAME,
        'id': By.ID,
        'class': By.CLASS_NAME
    }

    # 邮件信息
    EMAIL_INFO = {
        'username': 'xxxxxxx@qq.com',  # 切换成你自己的地址
        'password': 'QQ邮箱授权码',
        'smtp_host': 'smtp.qq.com',
        'smtp_port': 465
    }

    # 收件人
    ADDRESSEE = [
        'xxxxxxxx@qq.com',
    ]

    @property
    def log_file(self):
        """日志目录"""
        log_dir = os.path.join(self.BASE_DIR, 'logs')
        if not os.path.exists(log_dir):
            os.makedirs(log_dir)
        return os.path.join(log_dir, '{}.log'.format(dt_strftime()))

    @property
    def ini_file(self):
        """配置文件"""
        ini_file = os.path.join(self.BASE_DIR, 'config', 'config.ini')
        if not os.path.exists(ini_file):
            raise FileNotFoundError("配置文件%s不存在!" % ini_file)
        return ini_file


cm = ConfigManager()
if __name__ == '__main__':
    print(cm.BASE_DIR)

【注意】:QQ邮箱授权码:点击查看生成教程

2)config.ini

在项目 config 目录新建一个 config.ini 文件,里面暂时先放入需要测试的URL。

[HOST]
HOST = https://www.baidu.com

3)读取配置文件

①配置文件创建好了,接下来我们需要读取这个配置文件以使用里面的信息。
②使用python内置的 configparser 模块对 config.ini 文件信息进行了读取。
③对于测试url值的提取,使用python高阶语法 @property 属性值,写法更简单。
④在 common 目录中新建一个 readconfig.py 文件。

import configparser
from config.conf import cm

HOST = 'HOST'


class ReadConfig(object):
    """配置文件"""

    def __init__(self):
        self.config = configparser.RawConfigParser()  # 当有%的符号时请使用Raw读取
        self.config.read(cm.ini_file, encoding='utf-8')

    def _get(self, section, option):
        """获取"""
        return self.config.get(section, option)

    def _set(self, section, option, value):
        """更新"""
        self.config.set(section, option, value)
        with open(cm.ini_file, 'w') as f:
            self.config.write(f)

    @property
    def url(self):
        return self._get(HOST, HOST)


ini = ReadConfig()

if __name__ == '__main__':
    print(ini.url)

4、记录操作日志

在 utils 目录中新建 logger.py 文件。

import logging
from config.conf import cm


class Log:
    def __init__(self):
        self.logger = logging.getLogger()
        if not self.logger.handlers:
            self.logger.setLevel(logging.DEBUG)

            # 创建一个handle写入文件
            fh = logging.FileHandler(cm.log_file, encoding='utf-8')
            fh.setLevel(logging.INFO)

            # 创建一个handle输出到控制台
            ch = logging.StreamHandler()
            ch.setLevel(logging.INFO)

            # 定义输出的格式
            formatter = logging.Formatter(self.fmt)
            fh.setFormatter(formatter)
            ch.setFormatter(formatter)

            # 添加到handle
            self.logger.addHandler(fh)
            self.logger.addHandler(ch)

    @property
    def fmt(self):
        return '%(levelname)s\t%(asctime)s\t[%(filename)s:%(lineno)d]\t%(message)s'


log = Log().logger

if __name__ == '__main__':
    log.info('hello world')

5、项目中元素相关

POM模型:PO模式详解

元素定位:①selenium UI自动化测试xpath定位详解 ;②selenium UI自动化测试之CSS元素定位语法详解

6、管理页面元素

1)新建page_element目录并在该目录下新建search.yaml文件

①本教程选择的测试地址是百度首页,所以对应的元素也是百度首页的。
②项目框架设计中有一个page_element 目录就是专门来存放定位元素的文件的。
③通过对各种配置文件的对比,我在这里选择的是YAML文件格式。其易读,交互性好。
④在 page_element 中新建一个 search.yaml 文件。文件内容如下:

搜索框:"id==kw"
候选:"css==.bdsug-overflow"
搜索候选:"css==#form div li"
搜索按钮:"id==su"

2)在common目录中创建readelement.py文件。

①在 common 目录中创建 readelement.py 文件。实现了定位元素的存储和调用。文件内容如下:

②通过特殊方法 getitem 实现调用任意属性,读取yaml中的值。参考博客:python之__getitem__ 方法学习与使用 || python方法下划线命名规则

import os
import yaml
from config.conf import cm


class Element(object):
    """获取元素"""

    def __init__(self, name):
        self.file_name = '%s.yaml' % name
        self.element_path = os.path.join(cm.ELEMENT_PATH, self.file_name)
        if not os.path.exists(self.element_path):
            raise FileNotFoundError("%s 文件不存在!" % self.element_path)
        with open(self.element_path, encoding='utf-8') as f:
            self.data = yaml.safe_load(f)

    def __getitem__(self, item):
        """获取属性"""
        data = self.data.get(item)
        if data:
            name, value = data.split('==')
            return name, value
        raise ArithmeticError("{}中不存在关键字:{}".format(self.file_name, item))


if __name__ == '__main__':
    search = Element('search')
    print(search['搜索框'])

3)新建script脚本文件目录并新建inspect.py文件

在 script 脚本文件目录中创建 inspect.py 文件,对所有的元素yaml文件内容进行审查。

import os
import yaml
from config.conf import cm
from utils.times import running_time


@running_time
def inspect_element():
    """检查所有的元素是否正确
    只能做一个简单的检查
    """
    for files in os.listdir(cm.ELEMENT_PATH):
        _path = os.path.join(cm.ELEMENT_PATH, files)
        with open(_path, encoding='utf-8') as f:
            data = yaml.safe_load(f)
        for k in data.values():
            try:
                pattern, value = k.split('==')
            except ValueError:
                raise Exception("元素表达式中没有`==`")
            if pattern not in cm.LOCATE_MODE:
                raise Exception('%s中元素【%s】没有指定类型' % (_path, k))
            elif pattern == 'xpath':
                assert '//' in value,\
                    '%s中元素【%s】xpath类型与值不配' % (_path, k)
            elif pattern == 'css':
                assert '//' not in value, \
                    '%s中元素【%s]css类型与值不配' % (_path, k)
            else:
                assert value, '%s中元素【%s】类型与值不匹配' % (_path, k)


if __name__ == '__main__':
    inspect_element()

7、封装Selenium基类

①工厂模式的写法:很直白,简单,又明了。

【创建driver对象,打开百度网页,搜索selenium,点击搜索,然后停留5秒,查看结果,最后关闭浏览器。】

import time
from selenium import webdriver


driver = webdriver.Chrome()
driver.get('https://www.baidu.com')
driver.find_element_by_xpath("//input[@id='kw']").send_keys('selenium')
driver.find_element_by_xpath("//input[@id='su']").click()
time.sleep(5)
driver.quit()

②那为什么要封装selenium的方法呢?

首先我们上述这种较为原始的方法,基本不适用于平时做UI自动化测试的:因为在UI界面实际运行情况远远比较复杂,可能因为网络原因,或者控件原因,我们元素还没有显示出来,就进行点击或者输入。

所以我们需要封装selenium方法,通过内置的显式等待或一定的条件语句,才能构建一个稳定的方法。而且把selenium方法封装起来,有利于平时的代码维护。

新建page目录并创建webpage.py文件

①在 page 目录创建 webpage.py 文件。文件内容如下:

②在文件中我们对主要用了显示等待对selenium的 click , send_keys 等方法,做了二次封装。提高了运行的成功率。

from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from selenium.common.exceptions import TimeoutException

from config.conf import cm
from utils.times import sleep
from utils.logger import log

"""
selenium基类
本文件存放了selenium基类的封装方法
"""


class WebPage(object):
    """selenium基类"""

    def __init__(self, driver):
        # self.driver = webdriver.Chrome()
        self.driver = driver
        self.timeout = 20
        self.wait = WebDriverWait(self.driver, self.timeout)

    def get_url(self, url):
        """打开网址并验证"""
        self.driver.maximize_window()
        self.driver.set_page_load_timeout(60)
        try:
            self.driver.get(url)
            self.driver.implicitly_wait(10)
            log.info("打开网页:%s" % url)
        except TimeoutException:
            raise TimeoutException("打开%s超时请检查网络或网址服务器" % url)

    @staticmethod
    def element_locator(func, locator):
        """元素定位器"""
        name, value = locator
        return func(cm.LOCATE_MODE[name], value)

    def find_element(self, locator):
        """寻找单个元素"""
        return WebPage.element_locator(lambda *args: self.wait.until(
            EC.presence_of_element_located(args)), locator)

    def find_elements(self, locator):
        """查找多个相同的元素"""
        return WebPage.element_locator(lambda *args: self.wait.until(
            EC.presence_of_all_elements_located(args)), locator)

    def elements_num(self, locator):
        """获取相同元素的个数"""
        number = len(self.find_elements(locator))
        log.info("相同元素:{}".format((locator, number)))
        return number

    def input_text(self, locator, txt):
        """输入(输入前先清空)"""
        sleep(0.5)
        ele = self.find_element(locator)
        ele.clear()
        ele.send_keys(txt)
        log.info("输入文本:{}".format(txt))

    def is_click(self, locator):
        """点击"""
        self.find_element(locator).click()
        sleep()
        log.info("点击元素:{}".format(locator))

    def element_text(self, locator):
        """获取当前的text"""
        _text = self.find_element(locator).text
        log.info("获取文本:{}".format(_text))
        return _text

    @property
    def get_source(self):
        """获取页面源代码"""
        return self.driver.page_source

    def refresh(self):
        """刷新页面F5"""
        self.driver.refresh()
        self.driver.implicitly_wait(30)

8、创建页面对象

新建page_object目录并创建一个searchpage.py文件

①在 page_object 目录下创建一个 searchpage.py 文件。

②在该文件中我们对,输入搜索关键词,点击搜索,搜索联想,进行了封装。【在平时中我们应该养成写注释的习惯,因为过一段时间后,没有注释,代码读起来很费劲。】

9、应用pytest测试框架

pytest.ini文件创建

①pytest项目中的配置文件,可以对pytest执行过程中操作做全局控制。
②在项目根目录新建 pytest.ini 文件。文件内容如下:

[pytest]
addopts = --html=report.html --self-contained-html

③addopts 指定执行时的其他参数说明:

  • –html=report/report.html --self-contained-html 生成pytest-html带样式的报告
  • -s 输出我们用例中的调式信息
  • -q 安静的进行测试
  • -v 可以输出用例更加详细的执行信息,比如用例所在的文件及用例名称等

10、编写测试用例

新建TestCase目录并创建test_search.py文件

①在 TestCase 目录中创建 test_search.py 文件。文件内容如下:
② pytest.fixture装饰器实现了和unittest的setup,teardown一样的前置启动,后置清理的装饰器。

③第一个测试用例:实现了在百度搜索selenium关键字,并点击搜索按钮,并在搜索结果中,用正则查找结果页源代码,返回数量大于10我们就认为通过。

④第二个测试用例:实现了百度搜索selenium关键字,然后断言搜索候选中的所有结果有没有selenium关键字。

import re
import pytest
from utils.logger import log
from common.readconfig import ini
from page_object.searchpage import SearchPage


class TestSearch:
    @pytest.fixture(scope='function', autouse=True)
    def open_baidu(self, drivers):
        """打开百度"""
        search = SearchPage(drivers)
        search.get_url(ini.url)

    def test_001(self, drivers):
        """搜索"""
        search = SearchPage(drivers)
        search.input_search("selenium")
        search.click_search()
        result = re.search(r'selenium', search.get_source)
        log.info(result)
        assert result

    def test_002(self, drivers):
        """测试搜索候选"""
        search = SearchPage(drivers)
        search.input_search("selenium")
        log.info(list(search.imagine))
        assert all(["selenium" in i for i in search.imagine])


if __name__ == '__main__':
    pytest.main(['TestCase/test_search.py'])

conftest.py

①在项目根目录下新建一个 conftest.py 文件。

②conftest.py是测试框架pytest的胶水文件,里面用到了fixture函数,封装并传递出了driver。

import pytest
from py.xml import html
from selenium import webdriver


driver = None


@pytest.fixture(scope='session', autouse=True)
def drivers(request):
    """
    
    :param request: python内置的fixture函数,本函数中用来注册终结函数
    :return: 返回driver实例
    """
    global driver
    if driver is None:
        driver = webdriver.Chrome()
        driver.maximize_window()

    def fn():
        driver.quit()

    request.addfinalizer(fn)
    return driver


@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_makereport(item):
    """
    当测试失败的时候,自动截图,展示到html报告中
    :param item:
    """
    pytest_html = item.config.pluginmanager.getplugin('html')
    outcome = yield
    report = outcome.get_result()
    report.description = str(item.function.__doc__)
    extra = getattr(report, 'extra', [])

    if report.when == 'call' or report.when == "setup":
        xfail = hasattr(report, 'wasxfail')
        if (report.skipped and xfail) or (report.failed and not xfail):
            file_name = report.nodeid.replace("::", "_") + ".png"
            screen_img = _capture_screenshot()
            if file_name:
                html = '<div><img src="data:image/png;base64,%s" alt="screenshot" style="width:1024px;height:768px;" ' \
                       'οnclick="window.open(this.src)" align="right"/></div>' % screen_img
                extra.append(pytest_html.extras.html(html))
        report.extra = extra


def pytest_html_results_table_header(cells):
    cells.insert(1, html.th('用例名称'))
    cells.insert(2, html.th('Test_nodeid'))
    cells.pop(2)


def pytest_html_results_table_row(report, cells):
    cells.insert(1, html.td(report.description))
    cells.insert(2, html.td(report.nodeid))
    cells.pop(2)


def pytest_html_results_table_html(report, data):
    if report.passed:
        del data[:]
        data.append(html.div('通过的用例未捕获日志输出.', class_='empty log'))


def _capture_screenshot():
    '''
    截图保存为base64
    :return:
    '''
    return driver.get_screenshot_as_base64()

11、发送邮件

①当项目执行完成之后,需要发送到自己或者其他人邮箱里查看结果。
②编写发送邮件的模块。
③在 utils 目录中新建 send_mail.py 文件,文件内容如下:

import zmail
from config.conf import cm


def send_report():
    """发送报告"""
    with open(cm.REPORT_FILE, encoding='utf-8') as f:
        content_html = f.read()
    try:
        mail = {
            'from': 'xxxxxx@qq.com',
            'subject': '最新的测试报告邮件',
            'content_html': content_html,
            'attachments': [cm.REPORT_FILE, ]
        }
        server = zmail.server(*cm.EMAIL_INFO.values())
        server.send_mail(cm.ADDRESSEE, mail)
        print("测试邮件发送成功!")
    except Exception as e:
        print("Error: 无法发送邮件,{}!", format(e))


if __name__ == "__main__":
    '''请先在config/conf.py文件设置QQ邮箱的账号和密码'''
    send_report()

④在 config/conf.py 文件中设置我们自己的QQ邮箱账号以及QQ邮箱授权码。运行 send_report() 函数。

最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:

这些资料,对于做【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!凡事要趁早,特别是技术行业,一定要提升技术功底。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2042243.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

透明加密软件排行榜前十名(2024年10大好用的透明加密软件推荐)

在当今数字化的时代&#xff0c;数据的安全性和保密性已经成为了企业和个人最为关注的问题之一。随着信息技术的飞速发展&#xff0c;各种数据泄露事件层出不穷&#xff0c;给企业和个人带来了巨大的损失。在这样的背景下&#xff0c;透明加密软件应运而生&#xff0c;成为了保…

商家转账到零钱申请必过教程2024

在微信作为重要的营销场景的当下&#xff0c;微信支付的商家转账到零钱功能对于众多企业来说具有重要意义。要顺利开通该接口&#xff0c;需要注意以下几个要点。 首先&#xff0c;需要公司主体资质。申请主体必须是公司&#xff0c;个体工商户暂无法申请。同时&#xff0c;要确…

8.15成都市计量院面试问答

&#x1f416; Q&#xff1a;为什么要选择计量检定测试院&#xff1f; A&#xff1a;市计量院具备多项资质认定和计量认证项目&#xff0c;选择成都市计量检定测试院&#xff0c;意味着接触前沿技术&#xff0c;积累丰富经验&#xff0c;服务社会公益&#xff0c;参与创新研发&…

spring揭秘01-spring容器启动过程分析

文章目录 【README】【1】Spring容器根据配置元素组装可用系统的过程【2】BeanFactoryPostProcessor-Bean工厂后置处理器【2.1】属性占位符配置器使用场景代码【2.2】CustomerEditorConfigurer-自定义编辑器配置器【2.3】自定义编属性编辑器案例代码 【README】 本文总结自《s…

为什么electron占用空间大,而Tauri占用小,他们不都是封装Chromium吗

Electron 和 Tauri&#xff08;使用 WebView&#xff09;的确都涉及嵌入浏览器引擎来渲染 HTML、CSS 和 JavaScript&#xff0c;但它们的架构和设计有显著不同&#xff0c;这导致了它们在应用程序体积和资源占用上的差异。以下是一些关键的原因&#xff1a; 1. 嵌入的浏览器引…

【中等】 猿人学web第一届 第6题 js混淆-回溯

文章目录 请求流程请求参数 加密参数定位r() 方法z() 方法 加密参数还原JJENCOde js代码加密环境检测_n("jsencrypt")12345 计算全部中奖的总金额请求代码注意 请求流程 请求参数 打开 调试工具&#xff0c;查看数据接口 https://match.yuanrenxue.cn/api/match/6 请…

MySQL运维-分库分表

介绍 问题分析 拆分策略 垂直拆分 水平拆分 实现技术 Mycat概述 介绍 概念介绍 Mycat配置 schema.xml schema标签 schema标签&#xff08;table&#xff09; datanode标签 datahost标签 rule.xml sever.xml system标签 user标签 Mycat分片 分片规则-范围 分片规则-取模 分…

linux部署elasticserch单节点

简介 Elasticsearch概述&#xff1a;Elasticsearch是一个建立在Apache Lucene之上的分布式、实时文档存储搜索引擎&#xff0c;它能够胜任上百个服务节点的扩展&#xff0c;并支持PB级别的结构化或非结构化数据。 Lucene与Elasticsearch&#xff1a;简要介绍Lucene作为搜索引擎…

分布式中的CAP理论是什么?BASE理论是什么?看完你就彻底懂啦

CAP 理论 CAP理论是分布式系统理论中的一个重要概念&#xff0c;它阐述了在分布式计算环境中&#xff0c;一致性&#xff08;Consistency&#xff09;、可用性&#xff08;Availability&#xff09;和分区容错性&#xff08;Partition Tolerance&#xff09;三者之间的权衡关系…

深化解析:企业内耗的解决之道

在缺乏有效的冲突解决机制下&#xff0c;企业内部冲突难以得到妥善处理&#xff0c;这加剧了内耗&#xff0c;破坏了团队协作的和谐氛围。而当工作环境充满紧张和压力时&#xff0c;员工容易陷入焦虑和疲劳的困境&#xff0c;进而影响工作效率和团队士气。 当员工感受不到应有…

拯救中医 刻不容缓

文&#xff5c;琥珀食酒社 作者 | 积溪 “真是毫无底线” “这是挂羊头卖狗肉” “这钱也赚&#xff0c;华为太让人失望了” 看到网上的这些评论 我的拳头都硬了 华为进军中医药产业 给咱中医药打造独一无二的人工智能大模型 让中医彻底摆脱西方的围剿 这是多好的事情…

如何提取PDF其中的一页或多页?推荐4种方法!

工作中&#xff0c;我们经常需要用到PDF文件&#xff0c;如果需要提取PDF文件中的其中一页或多页内容&#xff0c;要如何做呢&#xff1f;下面小编分享4种方法&#xff0c;看下哪种适合你&#xff01; 方法1&#xff1a;使用复制粘贴 如果PDF文件中需要提取的内容是纯文字&am…

一起学习LeetCode热题100道(42/100)

42.将有序数组转换为二叉搜索树(学习) 给你一个整数数组 nums &#xff0c;其中元素已经按 升序 排列&#xff0c;请你将其转换为一棵 平衡 二叉搜索树。 示例 1&#xff1a; 输入&#xff1a;nums [-10,-3,0,5,9] 输出&#xff1a;[0,-3,9,-10,null,5] 解释&#xff1a;[0…

python连接mysql+mycat读写分离实现

python连接mysql >>>import pymysql >>>connpymysql.connect(host"192.168.118.57",port3306,database"test",user"root",password"root") >>> cursorconn.cursor() >>> cursor.execute(&quo…

ISO 13485认证:医疗器械行业的质量护航者

在医疗器械行业&#xff0c;产品质量关乎生命。为确保每一件医疗器械的安全与可靠&#xff0c;ISO 13485认证作为全球公认的质量管理体系标准&#xff0c;正为无数企业提供强大的质量保障。对于企业来说&#xff0c;获得这一认证不仅是质量管理的提升&#xff0c;更是开拓全球市…

FFmpeg源码:av_log2函数分析

一、av_log2函数的声明 av_log2函数声明在FFmpeg源码&#xff08;本文演示用的FFmpeg源码版本为7.0.1&#xff09;的头文件libavutil/common.h中&#xff1a; #ifndef av_log2 av_const int av_log2(unsigned v); #endif 该函数作用是&#xff1a;求形参v是2的多少次幂&#…

【漏洞复现】某成科信票务管理系统 TicketManager SQL注入漏洞

声明&#xff1a;本文档或演示材料仅用于教育和教学目的。如果任何个人或组织利用本文档中的信息进行非法活动&#xff0c;将与本文档的作者或发布者无关。 一、漏洞描述 某成科信票务管理系统以私有/公有云为基础部署&#xff0c;实现了基础六管控多协同的智慧票务系统。该系…

企业的安全管家——加密软件

一、加密软件的重要性 数据安全保护&#xff1a;加密软件能够对企业数据进行加密处理&#xff0c;确保即使数据被窃取&#xff0c;也无法被未经授权的人员轻易解密。 合规性要求&#xff1a;许多行业和企业都面临严格的数据保护法规要求&#xff0c;如GDPR、HIPAA等&#xff…

和小米比起来希喂宠物空气净化器怎么样?

有宠物用哪个牌子空气净化机比较好呢&#xff1f;有宠物的家庭除异味、除毛、除菌需求比不养宠的更大&#xff0c;所以有宠物的家庭选空气净化器时一定要着重看这几点。 最近&#xff0c;我发现身边的朋友们都开始重视起家居空气质量&#xff0c;特别是有了宠物之后&#xff0…

Linux笔记 --- 文件属性

在操作文件时时常要获取文件的属性&#xff0c;比如类型、大小、权限、所有者等等信息&#xff0c;这些信息对于文件的传输管理等非常重要&#xff0c;而这些信息则可以通过下面这些函数获取。 这三个函数功能相同&#xff0c;区别在于&#xff0c;stat参数是文件名字&#xff…