目录

日志打印工具

实用 Helper 工具

sqlite 基础操作类

 字符串操作类

 UUID 生成器类

 文件基础操作

文件是否存在判断

文件大小获取

读文件

写文件

文件重命名

文件创建/删除

 父级目录的获取

目录创建/删除

附录(完整代码)


日志打印工具

        为了便于编写项目中能够快速定位程序的错误位置,因此编写一个日志输出宏工具,进行简单的日志打印。

  • 定义DEBUG,INFO,ERROR三个日志等级。
  • 日志格式:[日志等级][时间][文件][行号]    日志信息。
#pragma once#include <iostream>
#include <ctime>
#include <string>namespace jiuqi
{
#define DEBUG_LEVEL 0
#define INFO_LEVEL 1
#define ERROR_LEVEL 2#define DEFAULT_LEVEL DEBUG_LEVEL#define LOG(level, fmt, ...)                                                                                \{                                                                                                         \if (level >= DEFAULT_LEVEL)                                                                           \{                                                                                                     \std::string level_str;                                                                            \if (level == DEBUG_LEVEL)                                                                         \level_str = "DEBUG";                                                                          \else if (level == INFO_LEVEL)                                                                     \level_str = "INFO";                                                                           \else                                                                                              \level_str = "ERROR";                                                                          \time_t t = time(nullptr);                                                                         \struct tm *tm = localtime(&t);                                                                    \char time[32];                                                                                    \strftime(time, 31, "%H:%M:%S", tm);                                                               \printf("[%s][%s][%s:%d]\t" fmt "\n", level_str.c_str(), time,  __FILE__, __LINE__, ##__VA_ARGS__);\}                                                                                                     \}#define DEBUG(fmt, ...) LOG(DEBUG_LEVEL, fmt, ##__VA_ARGS__)
#define INFO(fmt, ...) LOG(INFO_LEVEL, fmt, ##__VA_ARGS__)
#define ERROR(fmt, ...) LOG(ERROR_LEVEL, fmt, ##__VA_ARGS__)
}

实用 Helper 工具

        Helper 工具类中要完成的是项目中需要的一些辅助零碎的功能代码实现,其中包括文
件的基础操作,字符串的额外操作等在项目中用到的零碎功能。

sqlite 基础操作类

        使用我们之前demo中编写过的sqlite类即可,将输出替换为日志打印。

    class SqliteHelper{public:typedef int (*sqliteCallback)(void *, int, char **, char **);SqliteHelper(const std::string &dbfile): _dbfile(dbfile), _handler(nullptr) {}bool open(int safe_level = SQLITE_OPEN_FULLMUTEX){int ret = sqlite3_open_v2(_dbfile.c_str(), &_handler, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | safe_level, nullptr);if (ret != SQLITE_OK){// std::cerr << "打开/创建数据库失败: " << sqlite3_errmsg(_handler) << std::endl;ERROR("%s:%s", "打开/创建数据库失败", sqlite3_errmsg(_handler));return false;}return true;}bool exec(const std::string &sql, sqliteCallback callback, void *arg){int ret = sqlite3_exec(_handler, sql.c_str(), callback, arg, nullptr);if (ret != SQLITE_OK){// std::cerr << sql << std::endl;// std::cerr << "执行语句失败: " << sqlite3_errmsg(_handler) << std::endl;ERROR("%s\n%s:%s", sql.c_str(), "执行语句失败: ", sqlite3_errmsg(_handler));return false;}return true;}void close(){if (_handler)sqlite3_close_v2(_handler);}private:std::string _dbfile;sqlite3 *_handler;};

 字符串操作类

        这里先实现字符串分割功能,主要是用于后续消息类型与队列类型,即绑定信息匹配的问题。

    class StrHelper{public:static size_t split(const std::string &str, const std::string &sep, std::vector<std::string> &result){size_t end = 0, start = 0;while (start < str.size()){end = str.find(sep, start);if (end == std::string::npos){result.push_back(str.substr(start));break;}if (end != start){result.push_back(str.substr(start, end - start));}start = end + sep.size();}return result.size();}};

说明:

  • 以sep作为分割符将str分割,结果存放在result中。
  • 返回分割子串的数量。
  • 注意,如果出现连续的分割符,我们必须跳过,即不允许插入空串。

 UUID 生成器类

        UUID(Universally Unique Identifier), 也叫通用唯一识别码,通常由 32 位 16 进制数字字符组成。

        在这里,uuid 生成,我们采用生成 8 个随机数字,加上 8 字节序号,共 16 字节数组生成 32 位 16 进制字符的组合形式来确保全局唯一的同时能够根据序号来分辨数据。

        为了获得随机数与稳定递增的序号(需支持高并发),我们介绍一下几个对象:

  • 随机数:
    • std::random_device对象:生成机器随机数,真随机数,但是效率较低。

    • std::mt19937_64对象:64位梅森旋转算法(Mersenne Twister)生成伪随机数,可以使用std::random_device对象生成的随机数作为种子。

    • std::uniform_int_distribution<int>对象:将随机数引擎的输出转换为均匀分布的整数。

  • 序号:
    • 使用size_t的原子计数器,使用fetch_add接口可以获得稳定递增的序号。
    class UUIDHelper{public:static std::string uuid(){std::random_device rd;std::mt19937_64 gernator(rd());std::uniform_int_distribution<int> distribution(0, 255);std::stringstream ss;for (int i = 1; i <= 8; i++){ss << std::setw(2) << std::setfill('0') << std::hex << distribution(gernator);if (i % 2 == 0)ss << '-';}static std::atomic<size_t> sep(1);size_t num = sep.fetch_add(1);for (int i = 7; i >= 0; i--){ss << std::setw(2) << std::setfill('0') << std::hex << ((num >> (i * 8)) & 0xff);if (i == 4)ss << '-';}return ss.str();}};

 文件基础操作

        我们将提供一系列文件操作,每个功能实现静态和非静态操作两种。

文件是否存在判断

        bool exists(){struct stat st;return (stat(_filename.c_str(), &st) == 0);}static bool exists(const std::string &filename){struct stat st;return (stat(filename.c_str(), &st) == 0);}

        使用stat接口可跨平台。

文件大小获取

        size_t size(){struct stat st;int ret = stat(_filename.c_str(), &st);if (ret < 0)return 0;return st.st_size;}static size_t size(const std::string &filename){struct stat st;int ret = stat(filename.c_str(), &st);if (ret < 0)return 0;return st.st_size;}

        同样使用stat接口,文件大小会被存放在结构体st中。

读文件

        bool read(std::string &body){size_t fsize = this->size();return read(body, 0, fsize);}bool read(std::string &body, size_t offset, size_t len){// 打开文件std::ifstream ifs(_filename, std::ios::binary | std::ios::in);if (!ifs.is_open()){ERROR("%s:文件打开失败", _filename.c_str());return false;}// 移动文件读取位置ifs.seekg(offset, std::ios::beg);// 读取文件body.resize(len);ifs.read(&body[0], len);if (!ifs.good()){ERROR("%s:文件读取失败", _filename.c_str());ifs.close();return false;}// 关闭文件返回ifs.close();return true;}static bool read(const std::string &filename, std::string &body){size_t fsize = size(filename);return read(filename, body, 0, fsize);}static bool read(const std::string &filename, std::string &body, size_t offset, size_t len){// 打开文件std::ifstream ifs(filename, std::ios::binary | std::ios::in);if (!ifs.is_open()){ERROR("%s:文件打开失败", filename.c_str());return false;}// 移动文件读取位置ifs.seekg(offset, std::ios::beg);// 读取文件body.resize(len);ifs.read(&body[0], len);if (!ifs.good()){ERROR("%s:文件读取失败", filename.c_str());ifs.close();return false;}// 关闭文件返回ifs.close();return true;}

        我们提供读取文件全部内容与读取文件特定位置特定长度内容的接口,有两点需要注意:

  1. 每次读取需要把读取缓冲区(即body)resize,否则会导致读取失败。
  2. ifstream对象的read接口第一个参数是char*类型的,不能使用string对象的c_str接口(因为返回的是const char*),解决办法是传入body第一个字符的地址。

写文件

        bool write(const std::string &body){size_t fsize = this->size();return write(body.c_str(), fsize, body.size());}bool write(const char *body, size_t offset, size_t len){// 打开文件std::fstream fs(_filename, std::ios::binary | std::ios::out | std::ios::in);if (!fs.is_open()){ERROR("%s:文件打开失败", _filename.c_str());return false;}// 移动文件写入位置fs.seekp(offset, std::ios::beg);// 写入文件fs.write(body, len);if (!fs.good()){ERROR("%s:文件读取失败", _filename.c_str());fs.close();return false;}fs.close();return true;}static bool write(const std::string &filename, const std::string &body){size_t fsize = size(filename);return write(filename, body.c_str(), fsize, body.size());}static bool write(const std::string &filename, const char *body, size_t offset, size_t len){// 打开文件std::fstream fs(filename, std::ios::binary | std::ios::out | std::ios::in);if (!fs.is_open()){ERROR("%s:文件打开失败", filename.c_str());return false;}// 移动文件写入位置fs.seekp(offset, std::ios::beg);// 写入文件fs.write(body, len);if (!fs.good()){ERROR("%s:文件读取失败", filename.c_str());fs.close();return false;}fs.close();return true;}

         这里实现了追加写入与在特定位置写入的功能,但是在特定位置写入会覆盖原本的内容,暂时未实现真正的插入功能。

        需要注意,因为要移动文件写位置,必须以读写方式打开文件。

文件重命名

        bool rename(const std::string new_name){return ::rename(_filename.c_str(), new_name.c_str());}static bool rename(const std::string old_name, const std::string new_name){return ::rename(old_name.c_str(), new_name.c_str());}

        使用库中的rename函数即可,一定要前加两个冒号,声明作用域。

文件创建/删除

        bool createFile(){return createFile(_filename);}static bool createFile(const std::string &filename){// 打开文件并立即关闭,创建空文件std::ofstream ofs(filename, std::ios::out);if (!ofs.is_open()){ERROR("%s:文件创建失败", filename.c_str());return false;}ofs.close();return true;}bool removeFile(){return removeFile(_filename);}static bool removeFile(const std::string &filename){return (::remove(filename.c_str()) == 0);}
  1. 文件创建:ofstrea的out打开模式:如果文件不存在就会创建。
  2. 文件删除,调用库中的remove接口即可。

 父级目录的获取

        std::string parentDirectory(){return parentDirectory(_filename);}static std::string parentDirectory(const std::string &filename){size_t pos = filename.find_last_of("/\\");if (pos == std::string::npos)return ".";std::string path = filename.substr(0, pos);return path;}

        寻找最后一个文件目录分割符即可,找不到就返回当前目录。

目录创建/删除

        bool createDirectory(){return createDirectory(parentDirectory(_filename));}static bool createDirectory(const std::string &path){size_t start = 0, end = 0;while (start < path.size()){end = path.find_first_of("/\\", start);if (end == std::string::npos){
#ifdef _WIN32int ret = _mkdir(path.c_str());
#elseint ret = mkdir(path.c_str(), 0775);
#endifif (ret != 0 && errno != EEXIST){ERROR("%s:目录创建失败,错误码: %d", path.c_str(), errno);return false;}break;}if (end == start){start += 1;continue;}std::string subpath = path.substr(0, end);if (exists(path)){start = end + 1;continue;}if (!subpath.empty()){
#ifdef _WIN32int ret = _mkdir(subpath.c_str());
#elseint ret = mkdir(subpath.c_str(), 0775);
#endifif (ret != 0 && errno != EEXIST){ERROR("%s:目录创建失败,错误码: %d", subpath.c_str(), errno);return false;}}start = end + 1;}return true;}bool removeDirectory(){return removeDirectory(parentDirectory(_filename));}static bool removeDirectory(const std::string &path){std::string cmd = "rm -rf " + path;return (system(cmd.c_str()) != -1);}
  1. 目录的创建:需要先创建父级目录才可以创建当前目录,注意如果遇到连续的文件目录分割符需要跳过。
  2. 目录的删除:调用系统命令即可。

附录(完整代码)

#pragma once#include <sqlite3.h>
#include <iostream>
#include <string>
#include <vector>
#include <random>
#include <sstream>
#include <fstream>
#include <atomic>
#include <sys/stat.h>
#include <iomanip>#ifdef _WIN32#include <direct.h>
#endif#include "log.hpp"namespace jiuqi
{class SqliteHelper{public:typedef int (*sqliteCallback)(void *, int, char **, char **);SqliteHelper(const std::string &dbfile): _dbfile(dbfile), _handler(nullptr) {}bool open(int safe_level = SQLITE_OPEN_FULLMUTEX){int ret = sqlite3_open_v2(_dbfile.c_str(), &_handler, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | safe_level, nullptr);if (ret != SQLITE_OK){// std::cerr << "打开/创建数据库失败: " << sqlite3_errmsg(_handler) << std::endl;ERROR("%s:%s", "打开/创建数据库失败", sqlite3_errmsg(_handler));return false;}return true;}bool exec(const std::string &sql, sqliteCallback callback, void *arg){int ret = sqlite3_exec(_handler, sql.c_str(), callback, arg, nullptr);if (ret != SQLITE_OK){// std::cerr << sql << std::endl;// std::cerr << "执行语句失败: " << sqlite3_errmsg(_handler) << std::endl;ERROR("%s\n%s:%s", sql.c_str(), "执行语句失败: ", sqlite3_errmsg(_handler));return false;}return true;}void close(){if (_handler)sqlite3_close_v2(_handler);}private:std::string _dbfile;sqlite3 *_handler;};class StrHelper{public:static size_t split(const std::string &str, const std::string &sep, std::vector<std::string> &result){size_t end = 0, start = 0;while (start < str.size()){end = str.find(sep, start);if (end == std::string::npos){result.push_back(str.substr(start));break;}if (end != start){result.push_back(str.substr(start, end - start));}start = end + sep.size();}return result.size();}};class UUIDHelper{public:static std::string uuid(){std::random_device rd;std::mt19937_64 gernator(rd());std::uniform_int_distribution<int> distribution(0, 255);std::stringstream ss;for (int i = 1; i <= 8; i++){ss << std::setw(2) << std::setfill('0') << std::hex << distribution(gernator);if (i % 2 == 0)ss << '-';}static std::atomic<size_t> sep(1);size_t num = sep.fetch_add(1);for (int i = 7; i >= 0; i--){ss << std::setw(2) << std::setfill('0') << std::hex << ((num >> (i * 8)) & 0xff);if (i == 4)ss << '-';}return ss.str();}};class FileHelper{public:FileHelper(const std::string &filename) : _filename(filename) {}bool exists(){struct stat st;return (stat(_filename.c_str(), &st) == 0);}static bool exists(const std::string &filename){struct stat st;return (stat(filename.c_str(), &st) == 0);}size_t size(){struct stat st;int ret = stat(_filename.c_str(), &st);if (ret < 0)return 0;return st.st_size;}static size_t size(const std::string &filename){struct stat st;int ret = stat(filename.c_str(), &st);if (ret < 0)return 0;return st.st_size;}bool read(std::string &body){size_t fsize = this->size();return read(body, 0, fsize);}bool read(std::string &body, size_t offset, size_t len){// 打开文件std::ifstream ifs(_filename, std::ios::binary | std::ios::in);if (!ifs.is_open()){ERROR("%s:文件打开失败", _filename.c_str());return false;}// 移动文件读取位置ifs.seekg(offset, std::ios::beg);// 读取文件body.resize(len);ifs.read(&body[0], len);if (!ifs.good()){ERROR("%s:文件读取失败", _filename.c_str());ifs.close();return false;}// 关闭文件返回ifs.close();return true;}static bool read(const std::string &filename, std::string &body){size_t fsize = size(filename);return read(filename, body, 0, fsize);}static bool read(const std::string &filename, std::string &body, size_t offset, size_t len){// 打开文件std::ifstream ifs(filename, std::ios::binary | std::ios::in);if (!ifs.is_open()){ERROR("%s:文件打开失败", filename.c_str());return false;}// 移动文件读取位置ifs.seekg(offset, std::ios::beg);// 读取文件body.resize(len);ifs.read(&body[0], len);if (!ifs.good()){ERROR("%s:文件读取失败", filename.c_str());ifs.close();return false;}// 关闭文件返回ifs.close();return true;}bool write(const std::string &body){size_t fsize = this->size();return write(body.c_str(), fsize, body.size());}bool write(const char *body, size_t offset, size_t len){// 打开文件std::fstream fs(_filename, std::ios::binary | std::ios::out | std::ios::in);if (!fs.is_open()){ERROR("%s:文件打开失败", _filename.c_str());return false;}// 移动文件写入位置fs.seekp(offset, std::ios::beg);// 写入文件fs.write(body, len);if (!fs.good()){ERROR("%s:文件读取失败", _filename.c_str());fs.close();return false;}fs.close();return true;}static bool write(const std::string &filename, const std::string &body){size_t fsize = size(filename);return write(filename, body.c_str(), fsize, body.size());}static bool write(const std::string &filename, const char *body, size_t offset, size_t len){// 打开文件std::fstream fs(filename, std::ios::binary | std::ios::out | std::ios::in);if (!fs.is_open()){ERROR("%s:文件打开失败", filename.c_str());return false;}// 移动文件写入位置fs.seekp(offset, std::ios::beg);// 写入文件fs.write(body, len);if (!fs.good()){ERROR("%s:文件读取失败", filename.c_str());fs.close();return false;}fs.close();return true;}bool rename(const std::string new_name){return ::rename(_filename.c_str(), new_name.c_str());}static bool rename(const std::string old_name, const std::string new_name){return ::rename(old_name.c_str(), new_name.c_str());}bool createFile(){return createFile(_filename);}static bool createFile(const std::string &filename){// 打开文件并立即关闭,创建空文件std::ofstream ofs(filename, std::ios::out);if (!ofs.is_open()){ERROR("%s:文件创建失败", filename.c_str());return false;}ofs.close();return true;}bool removeFile(){return removeFile(_filename);}static bool removeFile(const std::string &filename){return (::remove(filename.c_str()) == 0);}bool createDirectory(){return createDirectory(parentDirectory(_filename));}static bool createDirectory(const std::string &path){size_t start = 0, end = 0;while (start < path.size()){end = path.find_first_of("/\\", start);if (end == std::string::npos){
#ifdef _WIN32int ret = _mkdir(path.c_str());
#elseint ret = mkdir(path.c_str(), 0775);
#endifif (ret != 0 && errno != EEXIST){ERROR("%s:目录创建失败,错误码: %d", path.c_str(), errno);return false;}break;}if (end == start){start += 1;continue;}std::string subpath = path.substr(0, end);if (exists(path)){start = end + 1;continue;}if (!subpath.empty()){
#ifdef _WIN32int ret = _mkdir(subpath.c_str());
#elseint ret = mkdir(subpath.c_str(), 0775);
#endifif (ret != 0 && errno != EEXIST){ERROR("%s:目录创建失败,错误码: %d", subpath.c_str(), errno);return false;}}start = end + 1;}return true;}bool removeDirectory(){return removeDirectory(parentDirectory(_filename));}static bool removeDirectory(const std::string &path){std::string cmd = "rm -rf " + path;return (system(cmd.c_str()) != -1);}std::string parentDirectory(){return parentDirectory(_filename);}static std::string parentDirectory(const std::string &filename){size_t pos = filename.find_last_of("/\\");if (pos == std::string::npos)return ".";std::string path = filename.substr(0, pos);return path;}private:std::string _filename;};
}

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言:第07天笔记

C语言&#xff1a;第07天笔记 内容提要 循环结构 break与continue 综合案例《猜拳游戏》数组 数组的概念一维数组流程控制 break与continue break 功能&#xff1a; ① 用在switch中&#xff0c;用来跳出switch中的case语句&#xff1b;如果case没有break&#xff0c;可能会产生…

qt 中英文翻译 如何配置和使用

qt 中英文翻译 如何配置和使用 1. 在.pro文件中添加TRANSLATIONS 在你的 .pro 文件&#xff08;比如 HYAC_AAF_HOST.pro&#xff09;中添加&#xff1a; TRANSLATIONS \ zh\_CN.ts en\_US.ts这会告诉Qt项目你要支持中文和英文。 2. 提取可翻译文本&#xff08;生成ts文件&#…

Leetcode 710. 黑名单中的随机数

1.题目基本信息 1.1.题目描述 给定一个整数 n 和一个 无重复 黑名单整数数组 blacklist 。设计一种算法&#xff0c;从 [0, n - 1] 范围内的任意整数中选取一个 未加入 黑名单 blacklist 的整数。任何在上述范围内且不在黑名单 blacklist 中的整数都应该有 同等的可能性 被返…

RxJava 全解析:从原理到 Android 实战

在 Android 开发中&#xff0c;异步任务处理是绕不开的核心场景 —— 网络请求、数据库操作、文件读写等都需要在后台执行&#xff0c;而结果需回调到主线程更新 UI。传统的 “HandlerThread” 或 AsyncTask 不仅代码冗余&#xff0c;还容易陷入 “回调地狱”&#xff08;嵌套回…

OpenCV 官翻7 - 对象检测

文章目录ArUco 标记检测标记与字典标记物创建标记检测姿态估计选择字典预定义字典自动生成字典手动定义字典检测器参数阈值处理adaptiveThreshConstant轮廓过滤minMarkerPerimeterRate 与 maxMarkerPerimeterRatepolygonalApproxAccuracyRateminCornerDistanceRateminMarkerDis…

【Oracle】ORACLE OMF说明

ORACLE OMF (Oracle Managed Files) 是 Oracle 数据库提供的一项自动化文件管理功能。它的核心目的是简化数据库管理员&#xff08;DBA&#xff09;对数据库底层操作系统文件的管理工作。 以下是 OMF 的关键要点&#xff1a; 核心功能&#xff1a;自动命名和定位文件 在创建数据…

408考研逐题详解:2010年第35题——RIP协议

2010年第35题 某自治系统内采用 RIP 协议&#xff0c;若该自治系统内的路由器 R1 收到其邻居路由器 R2 的距离矢量&#xff0c;距离矢量中包含信息 <net1, 16>&#xff0c;则能得出的结论是&#xff08; &#xff09; A. R2 可以经过 R1 到达 net1&#xff0c;跳数为17 …

http与https的主要区别是什么?

什么是HTTP&#xff1f; HTTP&#xff08;HyperText Transfer Protocol&#xff0c;超文本传输协议&#xff09;是互联网上应用最为广泛的一种网络协议。它构成了Web数据通信的基础&#xff0c;并定义了客户端和服务器之间如何请求和传递网页信息。当您在浏览器中输入一个网址时…

STC89C52系列单片机简介

STC89C52系列单片机是由中国宏晶科技&#xff08;STC&#xff09;推出的一款新一代增强型8051内核单片机。它不仅继承了传统8051指令系统的兼容性&#xff0c;还在性能、功耗、抗干扰能力以及性价比方面进行了全面提升&#xff0c;广泛应用于各类嵌入式控制场景&#xff0c;如工…

基于 Docker 环境的 JupyterHub 详细部署手册

本文详细介绍基于Docker Compose的单机版JupyterHub部署方案&#xff0c;通过容器化技术实现多用户Notebook环境的快速搭建。方案采用官方JupyterHub镜像&#xff0c;配置11个端口映射&#xff08;18000-18010&#xff09;支持用户并发&#xff0c;通过数据卷挂载&#xff08;.…

常见的万能密码

目录 1. 通用SQL注入 2. 登录绕过 3. 密码重置 1. 通用SQL注入 or 11-- " or 11-- or aa " or "a""a or 11# " or 11# or 11/* " or 11/* or 11 " or "1""1 2. 登录绕过 admin-- admin or 11-- admin or aa …

04训练windows电脑低算力显卡如何部署pytorch实现GPU加速

大多数人用的电脑的显卡配置可能没有那么强,也就是说,我们很难享受到最新版本pytorch给我们带来的模型训练的速度和效率,为此,我们需要想办法在现有显卡情况下部署应用pytorch。 笔者有一台电脑,显卡算力很低,那么以该电脑为例,为大家介绍如何部署应用pytorch功能。 1…

PPT科研画图插件

PPT科研画图插件 iSlide- 让PPT设计简单起来 | PPT模板下载平台iSlide - 简单&#xff0c;好用的PPT插件&#xff01;拥有30万 原创可商用PPT模板&#xff0c;PPT主题素材&#xff0c;PPT案例&#xff0c;PPT图表&#xff0c;PPT图示&#xff0c;PPT图标&#xff0c;PPT插图和8…

CSS实现背景图片渐变透明

复合写法background: linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, #FFF 82.5%),url(https://example.com/image.jpg) center / cover no-repeat;参数说明&#xff1a;linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, #FFF 82.5%)创建从下至上的垂直渐变&#xff…

基于pyside6的通用机器人遥控控制界面

1. 前言 这两天需要帮一个朋友做一个简单的遥控控制界面&#xff0c;用于控制一台复合机器人(万向轮底盘机械臂旋转云台)&#xff0c;在这里分享一下 2. 开发框架 由于朋友那边的控制接口都是使用python来写的&#xff0c;所以我这里也使用py来完成这个遥控界面的开发。但其…

【iOS】ZARA仿写

【iOS】ZARA仿写 文章目录【iOS】ZARA仿写前言首页发现我的对姓名的更改总结前言 暑假第一个的任务仿写ZARA 虽然不是特别难却有很多小细节需要注意 首页 点进程序出现的就是整个项目最主要的一个点&#xff0c;即首页的无限轮播图&#xff0c;不管是自动轮播还是手动滑动&a…

Kubernetes Pod 调度基础

一、Replication Controller 和 ReplicaSet1、Replication ControllerReplication Controller&#xff08;复制控制器&#xff0c;RC&#xff09;RC 用来确保 Pod 副本数达到期望值&#xff0c;这样可以确保一个或多个同类 Pod 总是可用的。如果存在的 Pod 数量大于设定的值&am…

菜鸟的C#学习(二)

文章目录一、类的访问1、普通类继承抽象类2、普通类继承抽象类&#xff0c;抽象类继承接口&#xff0c;三者联系二、类中方法的访问2.1 抽象方法和虚方法2.2 虚方法和普通方法**1. 调用机制****2. 方法重写****3. 设计意图****4. 性能差异****5. 语法对比表****总结&#xff1a…

04 51单片机之数码管显示

文章目录1、前言2、数码管3、单个数码管引脚定义3-1、单个共阴极3-2、单个共阳极3-3、单个数码管引脚定义4、四位一体数码管引脚定义4-1、四位一体共阴极数码管4-2、四位一体共阳极数码管4-3、四位一体数码管引脚定义5、数码管原理图6、C51数组&#xff08;补充知识点&#xff…

【LLM】OpenRouter调用Anthropic Claude上下文缓存处理

背景 在使用OpenRouter调用Anthropic Claude大模型时&#xff0c;部分模型支持上下文缓存功能。当缓存命中时&#xff0c;调用成本会显著降低。虽然像DeepSeek这类模型自带上下文缓存机制&#xff0c;但本文主要针对构建Agent场景下&#xff0c;需要多次调用Anthropic Claude时…