项目实现:云备份③(配置文件加载模块、数据管理模块的实现)

news2024/11/13 12:42:48

云备份

  • 前言
  • 配置文件加载模块
    • 配置信息的设计
    • 单例文件配置类设计
  • 数据管理模块
    • 数据信息类设计
    • 数据管理类实现
    • 数据持久化存储
    • 初始化加载实现

前言

书接上回:云备份(实用工具类)实现后,接下来会逐步实现不同模块的功能。会频繁用到工具类,如果不熟悉的老铁还是先看看前面的内容,对接下来要讲解的模块实现会有比较好理解。

配置文件加载模块

配置信息的设计

  1. 热点时间判断:设定一个合适的时间,决定在这个时间过后的文件是非热点文件。对于非热点文件进行压缩存储。
  2. 文件下载 URL 前缀路径:通常这个路径是用来判断用户的下载请求,可能是下载文件请求,也可能是查看备份文件列表的请求。
  3. 压缩文件的后缀名:在这里默认将压缩后的文件后缀设置为 .lz
  4. 上传文件的存放路径:决定了用户上传文件的存储到服务器的哪里。
  5. 压缩包存放位置:对于非热点文件、压缩包 和 热点文件、普通文件要区分存储。决定了非热点文件、压缩文件的存储位置。
  6. 服务器备份信息存储到文件:记录备份文件信息,保证数据的持久化
  7. 服务器的监听IP、监听端口:当客户端运行到其他主机时,不再需要修改程序

单例文件配置类设计

这里的单例模式采用懒汉模式,对饿汉、懒汉单例模式的实现可以参考小编的这篇文章:特殊类设计

单例文件配置类是用来配置信息的,其中主要实现以下几个功能:

  • GetHotTime:提供热点判断时间
  • GetServerPort:提供服务器监听端口
  • GetServerIP:提供服务器监听IP
  • GetDownloadPrefix:提供下载的 URL 前缀路径
  • GetPackFileSuffix:提供压缩包后缀名
  • GetBackDir:提供备份文件的存放目录
  • GetPackDir:提供压缩包存放的目录
  • GetBackupFile:提供信息存储的文件

下面开始进行代码的编写。

  1. 首先创建 cloud.conf 配置文件,编写配置信息。使用的是Json格式进行编写:
{
	"hot_time" : 30,
	"server_port" : 9090,
	"server_ip" : "xxx.xxx.xxx.xxx",
	"download_prefix" : "/download/",
	"packfile_suffix" : ".lz",
	"pack_dir" : "./packdir/",
	"back_dir" : "./backdir/",
	"backup_file" : "./cloud.dat"
}

这里的服务器 IP 设置按照个人需求进行改写,当然端口号也是。

  1. 单例文件配置类的实现,创建 config.hpp 文件进行代码的编写:
#ifndef CLOUD_HPP
#define CLOUD_HPP

#include <mutex>
#include "util.hpp"

namespace cloud
{
#define CONFIG_FILE "./cloud.conf"

    class Config
    {
    public:
        // 获取单例对象指针
        static Config *GetInstance()
        {
            // 双检查加锁
            if (_instance == nullptr)
            {
                // 加锁
                _mutex.lock();
                if (_instance == nullptr)
                {
                    return _instance = new Config();
                }
                // 解锁
                _mutex.unlock();
            }
        }

        //提供热点判断时间
        int GetHotTime() { return _hot_time; }
        //提供服务器监听端口
        int GetServerPort() { return _server_port; }
        //提供服务器监听IP
        std::string GetServerIP() { return _server_ip; }
        //提供下载的URL前缀路径 
        std::string GetDownloadPrefix() { return _download_prefix; }
        //提供压缩包后缀名
        std::string GetPackFileSuffix() { return _packfile_suffix; }
        //提供备份文件的存放目录
        std::string GetBackDir() { return _back_dir; }
        //提供压缩包存放的目录
        std::string GetPackDir() { return _pack_dir; }
        //提供信息存储的文件
        std::string GetBackupFile() { return _backup_file; }

    private:
        // 获取cloud.conf文件信息,进行初始化
        bool ReadConfigFile()
        {
            cloud::FileUtil fu(CONFIG_FILE);
            std::string body;
            // 提取文件信息
            if (fu.GetContent(&body) == false)
            {
                std::cout << "load config file failed!\n";
                return false;
            }
            // 将提取的内容进行反序列化操作
            Json::Value root;
            if (JsonUtil::UnSerialize(body, &root) == false)
            {
                std::cout << "parse config file failed!\n";
                return false;
            }
            // 初始化:
            _hot_time = root["hot_time"].asInt();
            _server_port = root["server_port"].asInt();
            _download_prefix = root["download_prefix"].asString();
            _packfile_suffix = root["packfile_suffix"].asString();
            _pack_dir = root["pack_dir"].asString();
            _back_dir = root["back_dir"].asString();
            _backup_file = root["backup_file"].asString();

            return true;
        }
        int _hot_time;                // 热点时间判断
        int _server_port;             // 服务器监听端口
        std::string _server_ip;       // 服务器监听IP
        std::string _download_prefix; // 文件下载的URL前缀路径
        std::string _packfile_suffix; // 压缩文件的后缀名
        std::string _pack_dir;        // 压缩包存放目录
        std::string _back_dir;        // 备份文件的存放目录
        std::string _backup_file;     // 提供信息存储的文件

    private:
        Config()
        {
            ReadConfigFile();
        }
        // 防止单例的拷贝与赋值
        Config(const Config &config) = delete;
        Config &operator=(const Config &config) = delete;
        static Config *_instance;
        static std::mutex _mutex;
    };
    // 静态成员的初始化:类外进行
    Config *Config::_instance = nullptr;
    std::mutex Config::_mutex;
}
#endif

测试代码:

#pragma once
#include "util.hpp"
#include "config.hpp"
void ConfigTest()
{
    // 实例化单例
    cloud::Config *config = cloud::Config::GetInstance();

    std::cout << config->GetHotTime() << std::endl;
    std::cout << config->GetServerPort() << std::endl;
    std::cout << config->GetServerIP() << std::endl;
    std::cout << config->GetDownloadPrefix() << std::endl;
    std::cout << config->GetPackFileSuffix() << std::endl;
    std::cout << config->GetBackDir() << std::endl;
    std::cout << config->GetPackDir() << std::endl;
    std::cout << config->GetBackupFile() << std::endl;
}
int main(int argc, char *argv[])
{
    ConfigTest();
    return 0;
}

实现效果:
在这里插入图片描述
可以看到,这里将 cloud.conf 文件内容进行了正常输出,初始化也没有问题。

数据管理模块

好的管理模式,在后期可以帮助我们去更好的处理大量的数据。

为了后期更好的管理数据,并且使用这些数据,首先要对文件的以下这些数据信息进行封装管理:

  1. 文件的实际存储路径:客户端要下载文件时,从这个文件中读取数据进行响应。
  2. 文件压缩包存放路径:对于非热点文件会被压缩处理,压缩包的路径也是需要管理的。当用户需要这个文件时,要先对压缩包进行解压,让后再读取响应的内容。
  3. 文件是否压缩的标志位:用于判断文件是否压缩
  4. 文件大小
  5. 文件最后一次访问时间
  6. 文件最后一次修改时间
  7. 文件访问URL中的资源路径path:/download/a.txt

数据信息类设计

在 src 文件下创建 data.hpp 文件,对 BackupInfo 数据信息类进行代码编写。

  • 实现 BackupInfo 数据信息类

BackupInfo 主要功能是对数据信息进行封装,实现如下:

#include "config.hpp"

namespace cloud
{
    struct BackupInfo
    {
        bool pack_flag;        // 压缩文件的标志位
        size_t fsize;          // 文件大小
        time_t mtime;          // 文件最后一次修改时间
        time_t atime;          // 文件最后一次访问时间
        std::string real_path; // 文件的实际存储路径
        std::string pack_path; // 文件压缩包存放路径
        std::string url;       // URL中的资源路径path

        //初始化信息
        bool NewBackupInfo(const std::string& realpath)
        {
            FileUtil fu(realpath);
            if(fu.Exists() == false)
            {
                std::cout << "new backupbnfo : file is not exists!\n";
                return false;
            }
            Config* config = Config::GetInstance();
            //获取配置文件信息
            std::string packdir = config->GetPackDir();
            std::string packsuffix = config->GetPackFileSuffix(); //获取压缩文件后缀
            std::string download_prefix = config->GetDownloadPrefix(); //文件下载路径

            pack_flag = false; //初始设置为普通文件
            //赋值处理
            fsize = fu.FileSize(); 
            mtime = fu.LastMTime();
            atime = fu.LastATime();
            real_path =  realpath; //文件实际所在的路径
            //./backdir/a.txt -> ./packdir/a.txt.lz
            pack_path = packdir + fu.FileName() + packsuffix; //压缩包路径
            //./backdir/a.txt -> /download/a.txt
            url = download_prefix + fu.FileName(); //文件下载路径
            return true;
        }
    };
}

测试代码:

#include "data.hpp"

void DataTest(const std::string &filename)
{
    cloud::BackupInfo info;
    info.NewBackupInfo(filename);
	//输出BackupInfo数据信息
    std::cout << info.pack_flag << std::endl;
    std::cout << info.fsize << std::endl;
    std::cout << info.mtime << std::endl;
    std::cout << info.atime << std::endl;
    std::cout << info.real_path << std::endl;
    std::cout << info.pack_path << std::endl;
    std::cout << info.url << std::endl;
}
int main(int argc, char *argv[])
{
    DataTest(argv[1]);
    return 0;
}

这里直接拿 src 当前目录下的文件进行测试,实现效果:
在这里插入图片描述

数据管理类实现

为了更快的访问数据信息,实现一个数据管理类。

在这里采用 hash 表在内存中管理数据;以 URL 的 path 路径作为key值;拿数据信息类 BackupInfo 对象作为为 val值。

其中,DataManager 数据管理类主要实现以下几个功能:

  1. Insert:支持插入新的数据信息
  2. Update:支持更新数据信息
  3. GetOneByUrl:通过URL资源路径查找对应文件的数据信息
  4. GetOneByRealPath:通过文件路径查找对应的数据信息
  5. GetAll:获取所有的文件数据信息
  • 实现 DataManager 数据管理类

在实现前要讲一点:由于数据可以被多人访问,但是对于写只能允许一个人进行操作。

由此要引入一个 pthread_rwlock_t 读写锁

  • 读写锁 允许多个线程同时读取共享资源,但只允许一个线程进行写操作

下面是 DataManager 类的实现代码:

#include "config.hpp"
#include <unordered_map>
#include <pthread.h>

class DataManager
{
public:
    DataManager()
    {
        // 初始化读写锁
        pthread_rwlock_init(&_rwlock, nullptr);
        // 将拷贝文件的信息进行初始化
        _backup_file = Config::GetInstance()->GetBackupFile();
    }

    ~DataManager()
    {
        // 销毁读写锁
        pthread_rwlock_destroy(&_rwlock);
    }
    // 插入数据信息
    bool Insert(const BackupInfo &info)
    {
        pthread_rwlock_wrlock(&_rwlock); // 上锁
        _table[info.url] = info;         // 数据不存在直接进行插入
        pthread_rwlock_unlock(&_rwlock); // 解锁

        return true;
    }
    // 更新数据信息
    bool UpDate(const BackupInfo &info)
    {
        pthread_rwlock_wrlock(&_rwlock); // 上锁
        _table[info.url] = info;         // 数据不存在直接进行插入,否则更新对应的内容
        pthread_rwlock_unlock(&_rwlock); // 解锁
        return true;
    }
    // 通过URL的文件资源路径,获取对应的备份文件的数据信息
    bool GetOneByUrl(const std::string &url, BackupInfo *info)
    {
        pthread_rwlock_wrlock(&_rwlock); // 上锁

        auto it = _table.find(url);
        if (it == _table.end())
        {
            // 没有找到
            pthread_rwlock_unlock(&_rwlock); // 解锁
            return false;
        }

        // 找到了
        *info = it->second;              // 迭代器的second就是val值
        pthread_rwlock_unlock(&_rwlock); // 解锁

        return true;
    }
    // 通过文件路径查找备份文件的数据信息
    bool GetOneByRealPath(const std::string &realpath, BackupInfo *info)
    {
        pthread_rwlock_wrlock(&_rwlock); // 上锁

        // 遍历整个_table
        auto it = _table.begin();
        while (it != _table.end())
        {
            if (it->second.real_path == realpath)
            {
                // 文件数据信息匹配到了
                *info = it->second;
                pthread_rwlock_unlock(&_rwlock); // 解锁
                return true;
            }
            ++it;
        }

        // 没有找到
        pthread_rwlock_unlock(&_rwlock); // 解锁
        return false;
    }
    //获取整个数据信息
    bool GetAll(std::vector<BackupInfo> *array) //输出型参数
    {
        pthread_rwlock_wrlock(&_rwlock); // 上锁

        //遍历整个_table
        auto it = _table.begin();
        while(it != _table.end())
        {
            //_table表中的val值都插入array中
            array->push_back(it->second);
            ++it;
        }
        pthread_rwlock_unlock(&_rwlock); // 解锁
        return true;
    }

private:
    pthread_rwlock_t _rwlock;                           // 读写锁
    std::string _backup_file;                           // 备份文件
    std::unordered_map<std::string, BackupInfo> _table; // 文件路径,数据信息对象
};

测试代码:

#include "data.hpp"

void PrintBackUpInfo(const cloud::BackupInfo &info)
{
    std::cout << info.pack_flag << std::endl;
    std::cout << info.fsize << std::endl;
    std::cout << info.mtime << std::endl;
    std::cout << info.atime << std::endl;
    std::cout << info.real_path << std::endl;
    std::cout << info.pack_path << std::endl;
    std::cout << info.url << std::endl;
}
void DataTest(const std::string &filename)
{
    cloud::BackupInfo info;
    info.NewBackupInfo(filename); // 初始化
    cloud::DataManager data;
    std::cout << "------------------Insert------------------------\n";
    data.Insert(info); // 将备份文件数据信息进行插入

    cloud::BackupInfo tmp;
    data.GetOneByUrl("/download/bundle.h", &tmp); // 查看下载目录下是否存在bundle.h文件
    // 打印对应的数据信息
    PrintBackUpInfo(tmp);
    std::cout << "------------------UpDate------------------------\n";
    // 修改刚刚插入数据的内容
    info.pack_flag = true;
    data.UpDate(info);
    std::vector<cloud::BackupInfo> array;
    data.GetAll(&array);
    for (auto &e : array)
    {
        PrintBackUpInfo(e);
    }
    std::cout << "------------------GetOneByRealPath------------------------\n";
    data.GetOneByRealPath(filename, &tmp);
    PrintBackUpInfo(tmp);
}
int main(int argc, char *argv[])
{
    DataTest(argv[1]);
    return 0;
}

在这里还是以 src 目录下的 bundle.h 文件为测试案例,测试结果如下:
在这里插入图片描述

数据持久化存储

为了持久化存储管理,采用Json序列化将所有的数据保存在文件中。

完善 DataManager 类,实现 Storage 成员函数。实现步骤如下:

  1. 获取 _table 中所有数据
  2. 将数据添加到 Json::Value 对象中
  3. 对 Json::Value 对象进行序列化操作
  4. 将序列化数据填写到文件

下面只展示当前功能代码,如下:

class DataManager
{
public:
	//...其他成员函数
	
    // 数据持久化操作
    bool Storage()
    {
        // 1.获取所有的数据信息
        std::vector<BackupInfo> array;
        GetAll(&array);
        // 2.将获取的数据添加到Json::Value对象
        Json::Value root;
        for (int i = 0; i < array.size(); i++)
        {
            Json::Value tmp;
            tmp["pack_flag"] = array[i].pack_flag;
            // Json不认识 time_t、size_t类型,需要强制类型转换
            tmp["fsize"] = (Json::Int64)array[i].fsize;
            tmp["mtime"] = (Json::Int64)array[i].mtime;
            tmp["atime"] = (Json::Int64)array[i].atime;
            tmp["real_path"] = array[i].real_path;
            tmp["pack_path"] = array[i].pack_path;
            tmp["url"] = array[i].url;
            // 整个数据不仅仅只有一份
            root[i].append(tmp);
        }
        // 3.序列化操作
        std::string body;
        if(JsonUtil::Serialize(root, &body) == false)
        {
            std::cout << "Data write failed!\n";
            return false;
        }
        // 4.将数据存储到文件
        FileUtil fu(_backup_file); // 写入到备份文件
        fu.SetContent(body);
        return true;
    }
private:
    pthread_rwlock_t _rwlock;                           // 读写锁
    std::string _backup_file;                           // 备份文件
    std::unordered_map<std::string, BackupInfo> _table; // 文件路径,数据信息对象
};

数据持久化操作,常用于新的数据插入后、数据更新后。

对此,需要对先前的 插入数据、更新数据的函数增添数据持久化功能,下面是 Insert、UpDate 函数修改后的代码:

// 插入数据信息
bool Insert(const BackupInfo &info)
{
    pthread_rwlock_wrlock(&_rwlock); // 上锁
    _table[info.url] = info;         // 数据不存在直接进行插入
    pthread_rwlock_unlock(&_rwlock); // 解锁

    //数据持久化
    Storage();
    return true;
}
// 更新数据信息
bool UpDate(const BackupInfo &info)
{
    pthread_rwlock_wrlock(&_rwlock); // 上锁
    _table[info.url] = info;         // 数据不存在直接进行插入,否则更新对应的内容
    pthread_rwlock_unlock(&_rwlock); // 解锁

    //数据持久化
    Storage();
    return true;
}

初始化加载实现

初始化程序运行时,从文件读取数据。

完善 DataManager 类,实现 InitLoad 成员函数。实现步骤如下:

  1. 将数据从文件中读取出来
  2. 反序列化操作
  3. 反序列化得到的数据添加到 _table 中

下面只展示当前功能代码,如下:

class DataManager
{
public:
	//...其他成员函数
	
	//数据初始化加载
    bool InitLoad()
     {
         //1.将数据从文件中读取出来
         FileUtil fu(_backup_file);
         if(fu.Exists() == false)
         {
             //文件不存在
             std::cout << "The back file does not exist\n";
             return false;
         }
         std::string body;
         fu.GetContent(&body);

         //2.反序列化
         Json::Value root;
         if(JsonUtil::UnSerialize(body, &root) == false)
         {
             std::cout << "Deserialization failed\n";
             return false;
         }

         //3.将反序列化的数据添加到_table
         for(int i = 0; i < root.size(); i++)
         {
             BackupInfo info;
             info.pack_flag = root[i]["pack_flag"].asBool();
             info.fsize = root[i]["fsize"].asInt64();
             info.mtime = root[i]["mtime"].asInt64();
             info.atime = root[i]["atime"].asInt64();
             info.pack_path = root[i]["pack_path"].asString();
             info.real_path = root[i]["real_path"].asString();
             info.url = root[i]["url"].asString();

             //将info添加到_table中
             Insert(info);
         }
         return true;
     }
private:
    pthread_rwlock_t _rwlock;                           // 读写锁
    std::string _backup_file;                           // 备份文件
    std::unordered_map<std::string, BackupInfo> _table; // 文件路径,数据信息对象
};

初始化一般都会在构造函数内部进行。实现初始化信息加载后,需要对构造函数进行功能添加:

 DataManager()
 {
     // 初始化读写锁
     pthread_rwlock_init(&_rwlock, nullptr);
     // 将拷贝文件的信息进行初始化
     _backup_file = Config::GetInstance()->GetBackupFile();
     //初始化加载
     InitLoad();
 }

到这里,数据管理模块的功能基本实现。

该篇文章主要实现了云备份项目的两个功能模块,由于篇幅过长,剩下模块的内容会在后续博客中体现。喜欢的老铁可以点赞 + 收藏!你们的关注是我持续更新的动力,感谢大家的观看。

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

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

相关文章

更主动的对话规划者:PPDPP论文解读

摘要 主动对话在大语言模型&#xff08;LLMs&#xff09;时代中是一个实际且具有挑战性的对话问题&#xff0c;其中对话策略规划是提升LLMs主动性的重要关键。现有的大多数研究通过各种提示方案或使用口头AI反馈迭代增强处理特定案例的能力&#xff0c;以实现LLMs的对话策略规…

元宇宙+教育:打造个性化、互动化学习生态系统!

近两年来&#xff0c;元宇宙风在全球迅速掀起了一股新浪潮。“元宇宙”成为各个行业的热门发展方向&#xff0c;各个行业正试图通过元宇宙寻求新的发展突破口&#xff0c;教育行业也不例外。 教育培训元宇宙作为一种前沿的教育模式&#xff0c;深度融合了虚拟现实、增强现实及…

SAP HCM HR_MAINTAIN_MASTERDATA自带解锁功能

导读 锁功能&#xff1a;在SAP HCM模块有针对人的加锁功能&#xff0c;今天遇到的一个问题是&#xff0c;人员无法被锁住&#xff0c;给我第一反应就是代码没有加锁&#xff0c;代码有问题&#xff0c;但是去看代码系统确实已经加锁&#xff0c;但是系统还是提示这个&#xff…

BPF 调度器 sched_ext 实现机制、调度流程及样例

本文地址&#xff1a;https://www.ebpf.top/post/bpf_sched_ext_dive_into 在文章 Linus 强势拍板合入: BPF 赋能调度器终成正果中&#xff0c;我们回顾了 BPF 在调度器在合入社区过程中的历程&#xff0c;补丁 V7 已经在为合并到 6.11 做好了准备&#xff0c;后续代码仓库也变…

4. 认识 LoRA:从线性层到注意力机制

如果你有使用过 AI 生图&#xff0c;那你一定对 LoRA 有印象&#xff0c;下图来自Civitai LoRA&#xff0c;上面有很多可供下载的LoRA模型。 你可能也曾疑惑于为什么只导入 LoRA 模型不能生图&#xff0c;读下去&#xff0c;你会解决它。 文章目录 为什么需要 LoRA&#xff1f;…

预训练数据指南:衡量数据年龄、领域覆盖率、质量和毒性的影响

前言 原论文&#xff1a;A Pretrainer’s Guide to Training Data: Measuring the Effects of Data Age, Domain Coverage, Quality, & Toxicity 摘要 预训练是开发高性能语言模型&#xff08;LM&#xff09;的初步和基本步骤。尽管如此&#xff0c;预训练数据的设计却严…

STM32 HAL freertos零基础(十一)中断管理

1、简介 在FreeRTOS中,中断管理是一个重要的方面,尤其是在嵌入式系统中。正确地处理中断可以确保系统的实时响应能力,并且能够在中断服务程序(ISR)中执行关键操作。FreeRTOS提供了一些机制来帮助开发者管理中断,并确保在多任务环境下中断处理的安全性和高效性。 任何中…

【AI大模型】Transformer模型:Postion Embedding概述、应用场景和实现方式的详细介绍。

一、位置嵌入概述 \1. 什么是位置嵌入&#xff1f; 位置嵌入是一种用于编码序列中元素位置信息的技术。在Transformer模型中&#xff0c;输入序列中的每个元素都会被映射到一个高维空间中的向量表示。然而&#xff0c;传统的自注意力机制并不包含位置信息&#xff0c;因此需要…

3CCD的工作原理

昨天看编辑送的一本《计算机视觉》中3CCD的工作原理错了&#xff0c;其实是百度百科错了&#xff0c;所以我想有人就照搬照抄错了。专业问题不要问百度&#xff0c;百度就是骗子一样的存在&#xff0c;这么多年就从来没有把心思放在做事上。3CCD通过光学棱镜分光后就已经是单色…

智能摄像头MP4格式化恢复方法

如果说生孩子扎堆&#xff0c;那很显然最近智能摄像头多碎片的恢复也扎堆了&#xff0c;这次恢复的是一个不知名的小品牌。其采用了mp4视频文件方案&#xff0c;不过这个案例的特殊之处在于其感染了病毒且不只一次&#xff0c;我们来看看这个小品牌的智能恢复头格式化的恢复方法…

Oracle发邮件功能:设置的步骤与注意事项?

Oracle发邮件配置教程&#xff1f;如何实现Oracle发邮件功能&#xff1f; Oracle数据库作为企业级应用的核心&#xff0c;提供了内置的发邮件功能&#xff0c;使得数据库管理员和开发人员能够通过数据库直接发送邮件。AokSend将详细介绍如何设置Oracle发邮件功能。 Oracle发邮…

基于web的 BBS论坛管理系统设计与实现

博主介绍&#xff1a;专注于Java .net php phython 小程序 等诸多技术领域和毕业项目实战、企业信息化系统建设&#xff0c;从业十五余年开发设计教学工作 ☆☆☆ 精彩专栏推荐订阅☆☆☆☆☆不然下次找不到哟 我的博客空间发布了1000毕设题目 方便大家学习使用 感兴趣的可以…

Linux 基本使用和 web 程序部署 ( 8000 字 Linux 入门 )

一&#xff1a;Linux 背景知识 1.1. Linux 是什么 Linux 是一个操作系统. 和 Windows 是 “并列” 的关系&#xff0c;经过这么多年的发展, Linux 已经成为世界第一大操作系统&#xff0c;安卓系统本质上就是 Linux. 1.2 Linux 发行版 Linux 严格意义来说只是一个 “操作系…

【楚怡杯】职业院校技能大赛 “云计算应用” 赛项样题三

某企业根据自身业务需求&#xff0c;实施数字化转型&#xff0c;规划和建设数字化平台&#xff0c;平台聚焦“DevOps开发运维一体化”和“数据驱动产品开发”&#xff0c;拟采用开源OpenStack搭建企业内部私有云平台&#xff0c;开源Kubernetes搭建云原生服务平台&#xff0c;选…

高亮下位机温湿度

效果如下&#xff1a; 如何对QTextEditor中的内容进行高亮和格式化显示&#xff1a; 首先我们要自定义一个类WenshiduHighlighter,继承自QSyntaxHighlighter实现构造函数&#xff0c;在构造函数中将需要匹配的正则和对应的格式创建&#xff0c;存到成员变量中重写父类的void h…

DNS应答报文分析

目录 DNS应答以太网数据帧 1. 数据链路层 1.1 以太网首部:(目的MAC地址6字节)(源MAC地址6字节)(帧类型2字节)共14字节 1.2 以太网首部数据 2. 网络层 2.1 IP协议头部共20个字节 2.2 IP协议头部数据 3. 传输层 3.1 UDP头部共8字节 3.2 UDP头部数据 4. 应用层 4.1 D…

低空经济第一站:无人机飞手人才培养技术详解

在低空经济蓬勃发展的背景下&#xff0c;无人机飞手作为直接操作者和应用者&#xff0c;其人才培养技术成为推动这一新兴经济形态持续健康发展的关键。以下是对无人机飞手人才培养技术的详细解析&#xff1a; 一、培养目标 无人机飞手的培养旨在培养具备扎实无人机操作技能、…

_Array类,类似于Vector,其实就是_string

例子&#xff1a; using namespace lf; using namespace std;int main() {_Array<int> a(10, -1);_Array<_string> s { _t("one"), _t("two") };_pcn(a);_pcn(s);} 结果&#xff1a; 源代码_Array.h&#xff1a; /***********************…

el-table 的单元格 + 图表 + 排序

<el-table border :data"tableDataThree" height"370px" style"width: 100%"><el-table-column :key"activeName 8" width"50" type"index" label"序号" align"center"></el…

macOS系统Homebrew工具安装及使用

1.打开Homebrew — The Missing Package Manager for macOS (or Linux) 2.复制安装命令到终端执行 复制 执行 3. 开始自动安装过程 4.安装成功 5.使用brew安装wget工具