wrap cpp variant as dll for c to use

包装c++的variant给c用

variant_wrapper.cpp

#include <variant>
#include <unordered_map>
#include <cstring>
#include <cstdio>
#include <new>
#include <memory>
#include <functional>
#include <cstdlib>// 类型ID定义
enum TypeId {TYPE_INVALID = -1,TYPE_INT = 0,TYPE_FLOAT = 1,TYPE_DOUBLE = 2,TYPE_STR = 3,TYPE_CUSTOM_BASE = 100
};struct CustomTypeOps {size_t size;void (*copy)(const void* src, void* dest);void (*destroy)(void* data);
};static std::unordered_map<TypeId, CustomTypeOps> g_type_registry;
static int g_next_custom_type = TYPE_CUSTOM_BASE;extern "C" TypeId cvariant_register_custom_type(size_t size, void (*copy)(const void*, void*),void (*destroy)(void*)) {TypeId id = static_cast<TypeId>(g_next_custom_type++);g_type_registry[id] = {size, copy, destroy};return id;
}// 变体数据存储(字符串使用char*并手动管理内存)
using VariantData = std::variant<int,float,double,char*,  // 改为char*以存储动态分配的字符串std::unique_ptr<void, std::function<void(void*)>>
>;typedef struct CVariant {VariantData data;TypeId type_id;
} CVariant;static const CustomTypeOps* get_custom_ops(TypeId id) {auto it = g_type_registry.find(id);return (it != g_type_registry.end()) ? &it->second : nullptr;
}extern "C" {CVariant* cvariant_create() {try {return new CVariant{{}, TYPE_INVALID};} catch (const std::bad_alloc&) {return nullptr;}}void cvariant_destroy(CVariant* var) {if (!var) return;// 关键修复:释放字符串内存if (var->type_id == TYPE_STR) {if (std::holds_alternative<char*>(var->data)) {char* str = std::get<char*>(var->data);free(str);  // 释放动态分配的字符串}}delete var;}void cvariant_set_int(CVariant* var, int value) {if (var) {// 清理原有字符串if (var->type_id == TYPE_STR && std::holds_alternative<char*>(var->data)) {free(std::get<char*>(var->data));}var->data = value;var->type_id = TYPE_INT;}}void cvariant_set_float(CVariant* var, float value) {if (var) {// 清理原有字符串if (var->type_id == TYPE_STR && std::holds_alternative<char*>(var->data)) {free(std::get<char*>(var->data));}var->data = value;var->type_id = TYPE_FLOAT;}}void cvariant_set_double(CVariant* var, double value) {if (var) {// 清理原有字符串if (var->type_id == TYPE_STR && std::holds_alternative<char*>(var->data)) {free(std::get<char*>(var->data));}var->data = value;var->type_id = TYPE_DOUBLE;}}// 关键修复:字符串存储改为动态分配void cvariant_set_str(CVariant* var, const char* value) {if (var) {// 先释放原有字符串if (var->type_id == TYPE_STR && std::holds_alternative<char*>(var->data)) {free(std::get<char*>(var->data));}// 复制字符串并存储if (value) {char* str = (char*)malloc(strlen(value) + 1);if (str) {strcpy(str, value);var->data = str;var->type_id = TYPE_STR;return;}}// 处理空字符串var->data = (char*)nullptr;var->type_id = TYPE_STR;}}int cvariant_set_custom(CVariant* var, TypeId type_id, const void* data) {if (!var || !data || type_id < TYPE_CUSTOM_BASE) return -1;// 清理原有字符串if (var->type_id == TYPE_STR && std::holds_alternative<char*>(var->data)) {free(std::get<char*>(var->data));}const auto* ops = get_custom_ops(type_id);if (!ops) return -1;void* storage = malloc(ops->size);if (!storage) return -1;ops->copy(data, storage);var->data = std::unique_ptr<void, std::function<void(void*)>>(storage,[type_id](void* ptr) {const auto* ops = get_custom_ops(type_id);if (ops) ops->destroy(ptr);free(ptr);});var->type_id = type_id;return 0;}TypeId cvariant_get_type(const CVariant* var) {return var ? var->type_id : TYPE_INVALID;}int cvariant_get_int(const CVariant* var) {if (var && var->type_id == TYPE_INT && std::holds_alternative<int>(var->data)) {return std::get<int>(var->data);}fprintf(stderr, "cvariant: 类型错误(预期int)\n");return 0;}float cvariant_get_float(const CVariant* var) {if (var && var->type_id == TYPE_FLOAT && std::holds_alternative<float>(var->data)) {return std::get<float>(var->data);}fprintf(stderr, "cvariant: 类型错误(预期float)\n");return 0.0f;}double cvariant_get_double(const CVariant* var) {if (var && var->type_id == TYPE_DOUBLE && std::holds_alternative<double>(var->data)) {return std::get<double>(var->data);}fprintf(stderr, "cvariant: 类型错误(预期double)\n");return 0.0;}const char* cvariant_get_str(const CVariant* var) {if (var && var->type_id == TYPE_STR && std::holds_alternative<char*>(var->data)) {return std::get<char*>(var->data);}fprintf(stderr, "cvariant: 类型错误(预期字符串)\n");return nullptr;}int cvariant_get_custom(const CVariant* var, void* dest) {if (!var || !dest || var->type_id < TYPE_CUSTOM_BASE) return -1;const auto* ops = get_custom_ops(var->type_id);if (!ops) return -1;if (std::holds_alternative<std::unique_ptr<void, std::function<void(void*)>>>(var->data)) {const void* src = std::get<std::unique_ptr<void, std::function<void(void*)>>>(var->data).get();ops->copy(src, dest);return 0;}return -1;}
}

cvariant.h

#ifndef CVARIANT_H
#define CVARIANT_H#include <stddef.h>#ifdef __cplusplus
extern "C" {
#endif// 类型ID(内置类型+自定义类型基值)
typedef enum {TYPE_INVALID = -1,TYPE_INT = 0,TYPE_FLOAT = 1,TYPE_DOUBLE = 2,TYPE_STR = 3,TYPE_CUSTOM_BASE = 100
} TypeId;// 不透明结构体(隐藏C++实现)
typedef struct CVariant CVariant;// 1. 核心管理函数
struct CVariant* cvariant_create();
void cvariant_destroy(struct CVariant* var);// 2. 自定义类型注册(返回类型ID)
//  - size: 类型大小
//  - copy: 复制函数(src->dest)
//  - destroy: 销毁函数(释放内部资源)
TypeId cvariant_register_custom_type(size_t size,void (*copy)(const void* src, void* dest),void (*destroy)(void* data));// 3. 设置值(内置类型)
void cvariant_set_int(struct CVariant* var, int value);
void cvariant_set_float(struct CVariant* var, float value);
void cvariant_set_double(struct CVariant* var, double value);
void cvariant_set_str(struct CVariant* var, const char* value);// 4. 设置值(自定义类型)
//  - type_id: 注册时返回的类型ID
//  - data: 指向自定义类型数据的指针
int cvariant_set_custom(struct CVariant* var, TypeId type_id, const void* data);// 5. 获取类型ID
TypeId cvariant_get_type(const struct CVariant* var);// 6. 获取值(内置类型)
int cvariant_get_int(const struct CVariant* var);
float cvariant_get_float(const struct CVariant* var);
double cvariant_get_double(const struct CVariant* var);
const char* cvariant_get_str(const struct CVariant* var);// 7. 获取值(自定义类型)
//  - dest: 用于接收数据的缓冲区(需提前分配足够空间)
int cvariant_get_custom(const struct CVariant* var, void* dest);#ifdef __cplusplus
}
#endif#endif // CVARIANT_H

build shared lib

g++ -shared -fPIC variant_wrapper.cpp -o cvariant.dll -Wl,--out-implib=libcvariant.a

conffget.c

#include "cvariant.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>// 手动实现strndup以兼容Windows平台
static char* strndup(const char* s, size_t n) {if (s == NULL) return NULL;// 计算实际需要复制的长度(不超过n且不超过原字符串长度)size_t len = strlen(s);if (n < len) len = n;// 分配内存(+1用于存储终止符)char* result = (char*)malloc(len + 1);if (result == NULL) return NULL;// 复制字符串并添加终止符memcpy(result, s, len);result[len] = '\0';return result;
}// 配置项节点(存储键值对)
typedef struct ConfigNode {char* section;         // 节名(如"server")char* key;             // 键名(如"port")CVariant* value;       // 值(多类型存储)struct ConfigNode* next; // 链表下一个节点
} ConfigNode;// 解析上下文
typedef struct {ConfigNode* head;      // 配置项链表头char* current_section; // 当前解析的节名
} ConfigParser;// 初始化解析器
static ConfigParser* parser_init() {ConfigParser* parser = (ConfigParser*)malloc(sizeof(ConfigParser));parser->head = NULL;parser->current_section = NULL;return parser;
}// 释放解析器资源
static void parser_free(ConfigParser* parser) {ConfigNode* node = parser->head;while (node) {ConfigNode* next = node->next;free(node->section);free(node->key);cvariant_destroy(node->value);free(node);node = next;}free(parser->current_section);free(parser);
}// 去除字符串首尾空格
static char* trim(char* str) {if (!str) return NULL;// 去除开头空格while (isspace((unsigned char)*str)) str++;// 去除结尾空格if (*str) {char* end = str + strlen(str) - 1;while (end > str && isspace((unsigned char)*end)) end--;*(end + 1) = '\0';}return str;
}// 识别值类型并存储到variant
static void set_value_by_type(CVariant* var, const char* value_str) {char* endptr;// 尝试识别为布尔值if (strcmp(value_str, "true") == 0 || strcmp(value_str, "yes") == 0) {cvariant_set_int(var, 1); // 1表示truereturn;}if (strcmp(value_str, "false") == 0 || strcmp(value_str, "no") == 0) {cvariant_set_int(var, 0); // 0表示falsereturn;}// 尝试识别为整数long int_val = strtol(value_str, &endptr, 10);if (*endptr == '\0') {cvariant_set_int(var, (int)int_val);return;}// 尝试识别为浮点数double float_val = strtod(value_str, &endptr);if (*endptr == '\0') {cvariant_set_double(var, float_val);return;}// 尝试识别为带引号的字符串(去除引号)if (value_str[0] == '"' && value_str[strlen(value_str)-1] == '"') {char* str_val = strndup(value_str + 1, strlen(value_str) - 2);cvariant_set_str(var, str_val);free(str_val);return;}// 否则视为普通字符串cvariant_set_str(var, value_str);
}// 添加配置项到链表
static void add_config_node(ConfigParser* parser, const char* key, const char* value) {if (!parser->current_section || !key || !value) return;ConfigNode* node = (ConfigNode*)malloc(sizeof(ConfigNode));node->section = strdup(parser->current_section);node->key = strdup(key);node->value = cvariant_create();set_value_by_type(node->value, value); // 自动识别类型node->next = parser->head;parser->head = node;
}// 解析INI文件
static int parse_ini_file(ConfigParser* parser, const char* filename) {FILE* f = fopen(filename, "r");if (!f) {fprintf(stderr, "无法打开文件: %s\n", filename);return -1;}char line[1024];int line_num = 0;while (fgets(line, sizeof(line), f)) {line_num++;char* content = trim(line);// 跳过空行和注释if (*content == '\0' || *content == ';' || *content == '#') continue;// 解析节名(如[server])if (*content == '[' && content[strlen(content)-1] == ']') {free(parser->current_section);parser->current_section = strndup(content + 1, strlen(content) - 2);continue;}// 解析键值对(如port=8080)char* eq_pos = strchr(content, '=');if (eq_pos) {*eq_pos = '\0';char* key = trim(content);char* value = trim(eq_pos + 1);add_config_node(parser, key, value);} else {fprintf(stderr, "警告: 无效行 %d: %s\n", line_num, content);}}fclose(f);return 0;
}// 查询配置项
static int query_config(ConfigParser* parser, const char* query) {// 拆分查询为节名和键名(格式:section.key)char* dot_pos = strchr(query, '.');if (!dot_pos) {fprintf(stderr, "查询格式错误,应为: 节名.键名\n");return -1;}char* section = strndup(query, dot_pos - query);char* key = strdup(dot_pos + 1);// 遍历链表查找配置项ConfigNode* node = parser->head;while (node) {if (strcmp(node->section, section) == 0 && strcmp(node->key, key) == 0) {// 根据类型输出值switch (cvariant_get_type(node->value)) {case TYPE_INT:// 布尔值特殊处理if (strcmp(key, "enable") == 0 || strcmp(key, "active") == 0) {printf("%s\n", cvariant_get_int(node->value) ? "true" : "false");} else {printf("%d\n", cvariant_get_int(node->value));}break;case TYPE_DOUBLE:printf("%g\n", cvariant_get_double(node->value));break;case TYPE_STR:printf("%s\n", cvariant_get_str(node->value));break;default:printf("未知类型\n");}free(section);free(key);return 0;}node = node->next;}fprintf(stderr, "未找到配置项: %s\n", query);free(section);free(key);return -1;
}// 列出所有配置项
static void list_all_configs(ConfigParser* parser) {ConfigNode* node = parser->head;while (node) {printf("[%s] %s = ", node->section, node->key);// 根据类型输出值switch (cvariant_get_type(node->value)) {case TYPE_INT:printf("%d (int)\n", cvariant_get_int(node->value));break;case TYPE_DOUBLE:printf("%g (float)\n", cvariant_get_double(node->value));break;case TYPE_STR:printf("%s (string)\n", cvariant_get_str(node->value));break;}node = node->next;}
}// 显示帮助
static void print_help(const char* progname) {printf("用法: %s [选项] <INI文件> [查询]\n", progname);printf("解析INI配置文件并查询值(兼容Linux风格)\n");printf("选项:\n");printf("  -l        列出文件中所有配置项及类型\n");printf("  -h        显示帮助信息\n");printf("查询格式: 节名.键名(如 'server.port')\n");printf("示例:\n");printf("  %s config.ini server.port      # 查询[server]节的port值\n", progname);printf("  %s -l app.ini                 # 列出app.ini所有配置项\n", progname);printf("  %s settings.ini log.enable    # 查询[log]节的enable值(布尔型)\n", progname);
}int main(int argc, char* argv[]) {if (argc < 2) {print_help(argv[0]);return 1;}int list_mode = 0;const char* filename = NULL;const char* query = NULL;// 解析命令行参数if (strcmp(argv[1], "-h") == 0) {print_help(argv[0]);return 0;} else if (strcmp(argv[1], "-l") == 0) {if (argc < 3) {print_help(argv[0]);return 1;}list_mode = 1;filename = argv[2];} else {filename = argv[1];query = (argc >= 3) ? argv[2] : NULL;if (!query) {print_help(argv[0]);return 1;}}// 解析配置文件ConfigParser* parser = parser_init();if (parse_ini_file(parser, filename) != 0) {parser_free(parser);return 1;}// 执行操作if (list_mode) {list_all_configs(parser);} else {query_config(parser, query);}// 清理资源parser_free(parser);return 0;
}

build confget.c

gcc -o confget.exe confget.c -L . -lcvariant

config.ini

; 示例配置文件
[server]
port = 8080
host = "localhost"
timeout = 30.5
enable = true[log]
path = "C:\logs"
level = info
max_size = 1024

sample output

# 查询[server]节的port(整数)
confget.exe config.ini server.port
# 输出:8080# 查询[server]节的timeout(浮点数)
confget.exe config.ini server.timeout
# 输出:30.5# 查询[server]节的enable(布尔值)
confget.exe config.ini server.enable
# 输出:true# 查询[log]节的path(字符串)
confget.exe config.ini log.path
# 输出:localhost# 列出所有配置项及类型
confget.exe -l config.ini
# 输出:
# [log] max_size = 1024 (int)
# [log] level = info (string)
# [log] path = C:\logs (string)
# [server] enable = 1 (int)
# [server] timeout = 30.5 (float)
# [server] host = localhost (string)
# [server] port = 8080 (int)

probe1.c

#include "cvariant.h"
#include <stdio.h>
#include <string.h>// 自定义类型定义(见上文)
typedef struct { int x; int y; char name[32]; } Point;
static void point_copy(const void* src, void* dest);
static void point_destroy(void* data);int main() {// 1. 注册自定义类型(获取类型ID)TypeId point_type = cvariant_register_custom_type(sizeof(Point),point_copy,point_destroy);printf("注册自定义类型 Point,ID: %d\n", point_type);// 2. 创建变体对象struct CVariant* var = cvariant_create();if (!var) {printf("创建变体失败\n");return 1;}// 3. 测试内置类型cvariant_set_int(var, 123);printf("类型: %d (预期0), 值: %d\n", cvariant_get_type(var), cvariant_get_int(var));cvariant_set_double(var, 3.1415926535);printf("类型: %d (预期2), 值: %lf\n", cvariant_get_type(var), cvariant_get_double(var));cvariant_set_str(var, "测试字符串");printf("类型: %d (预期3), 值: %s\n", cvariant_get_type(var), cvariant_get_str(var));// 4. 测试自定义类型(Point)Point p = {10, 20, "原点"};cvariant_set_custom(var, point_type, &p);if (cvariant_get_type(var) == point_type) {Point p_out;cvariant_get_custom(var, &p_out);printf("类型: %d (预期自定义ID), 值: (%d, %d, %s)\n",cvariant_get_type(var), p_out.x, p_out.y, p_out.name);}// 5. 清理cvariant_destroy(var);return 0;
}// 实现自定义类型的复制和销毁函数
static void point_copy(const void* src, void* dest) {const Point* s = (const Point*)src;Point* d = (Point*)dest;d->x = s->x;d->y = s->y;strncpy(d->name, s->name, sizeof(d->name)-1);
}static void point_destroy(void* data) {// 示例:无动态内存需要释放
}

probe2.c

#include "cvariant.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>// 1. 定义枚举类型(颜色)
typedef enum {RED,GREEN,BLUE,BLACK,WHITE
} Color;// 2. 定义联合体类型(通用数值)
typedef union {int i;float f;double d;
} Number;// 3. 定义包含枚举和联合体的复杂结构体
typedef struct {Color color;       // 枚举成员Number value;      // 联合体成员char name[64];     // 字符串成员
} ComplexData;// ------------------------------
// 枚举类型(Color)的操作函数
// ------------------------------
static void color_copy(const void* src, void* dest) {// 枚举本质是整数,直接复制内存*(Color*)dest = *(const Color*)src;
}static void color_destroy(void* data) {// 枚举无动态内存,无需额外操作
}// ------------------------------
// 联合体类型(Number)的操作函数
// ------------------------------
static void number_copy(const void* src, void* dest) {// 联合体整体复制memcpy(dest, src, sizeof(Number));
}static void number_destroy(void* data) {// 联合体无动态内存,无需额外操作
}// ------------------------------
// 复杂结构体(ComplexData)的操作函数
// ------------------------------
static void complexdata_copy(const void* src, void* dest) {const ComplexData* s = (const ComplexData*)src;ComplexData* d = (ComplexData*)dest;// 分别复制成员(枚举+联合体+字符串)d->color = s->color;d->value = s->value;  // 联合体直接复制strncpy(d->name, s->name, sizeof(d->name)-1);
}static void complexdata_destroy(void* data) {// 若结构体包含动态内存(如malloc的指针),需在此释放// 本示例无动态内存,仅作演示
}int main() {// 1. 注册自定义类型(获取类型ID)TypeId color_type = cvariant_register_custom_type(sizeof(Color), color_copy, color_destroy);TypeId number_type = cvariant_register_custom_type(sizeof(Number), number_copy, number_destroy);TypeId complex_type = cvariant_register_custom_type(sizeof(ComplexData), complexdata_copy, complexdata_destroy);printf("注册类型ID:\n");printf("  Color: %d\n", color_type);printf("  Number: %d\n", number_type);printf("  ComplexData: %d\n\n", complex_type);// 2. 创建变体对象struct CVariant* var = cvariant_create();if (!var) {fprintf(stderr, "创建变体失败\n");return 1;}// 3. 测试枚举类型(Color)Color my_color = BLUE;cvariant_set_custom(var, color_type, &my_color);if (cvariant_get_type(var) == color_type) {Color get_color;cvariant_get_custom(var, &get_color);printf("枚举类型测试:\n");printf("  存储的颜色: %d (BLUE对应值为2)\n", get_color);}// 4. 测试联合体类型(Number)Number my_num;my_num.f = 3.14159f;  // 存储float值cvariant_set_custom(var, number_type, &my_num);if (cvariant_get_type(var) == number_type) {Number get_num;cvariant_get_custom(var, &get_num);printf("\n联合体类型测试:\n");printf("  存储的float值: %f\n", get_num.f);}// 5. 测试复杂结构体(包含枚举和联合体)ComplexData my_complex = {.color = GREEN,.value = {.d = 99.99},  // 联合体存储double.name = "示例数据"};cvariant_set_custom(var, complex_type, &my_complex);if (cvariant_get_type(var) == complex_type) {ComplexData get_complex;cvariant_get_custom(var, &get_complex);printf("\n复杂结构体测试:\n");printf("  颜色枚举值: %d (GREEN对应值为1)\n", get_complex.color);printf("  联合体double值: %lf\n", get_complex.value.d);printf("  名称: %s\n", get_complex.name);}// 6. 清理资源cvariant_destroy(var);return 0;
}

probe3.c

#include "cvariant.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>// 带动态内存的结构体(需要手动释放)
typedef struct {int id;char* name;  // 动态分配的字符串(需malloc/free)float score;
} DynamicData;// 复制函数:深度复制动态内存
static void dynamicdata_copy(const void* src, void* dest) {const DynamicData* s = (const DynamicData*)src;DynamicData* d = (DynamicData*)dest;// 复制基础类型d->id = s->id;d->score = s->score;// 复制动态字符串(关键:手动分配新内存)if (s->name) {d->name = (char*)malloc(strlen(s->name) + 1);  // 分配内存strcpy(d->name, s->name);  // 复制内容} else {d->name = NULL;}
}// 销毁函数:释放动态内存(关键:防止内存泄漏)
static void dynamicdata_destroy(void* data) {DynamicData* d = (DynamicData*)data;if (d->name) {free(d->name);  // 释放动态字符串d->name = NULL;  // 避免野指针}
}int main() {// 1. 注册自定义类型(带动态内存)TypeId dynamic_type = cvariant_register_custom_type(sizeof(DynamicData),dynamicdata_copy,    // 深度复制动态内存dynamicdata_destroy  // 释放动态内存);printf("注册动态类型 ID: %d\n", dynamic_type);// 2. 创建原始数据(带动态内存)DynamicData original;original.id = 1001;original.name = (char*)malloc(strlen("Alice") + 1);  // 手动分配strcpy(original.name, "Alice");original.score = 95.5f;printf("原始数据: id=%d, name=%s, score=%.1f\n", original.id, original.name, original.score);// 3. 用变体类型存储动态数据struct CVariant* var = cvariant_create();cvariant_set_custom(var, dynamic_type, &original);// 4. 从变体中读取数据(验证复制是否正确)if (cvariant_get_type(var) == dynamic_type) {DynamicData copy;cvariant_get_custom(var, &copy);printf("从变体读取: id=%d, name=%s, score=%.1f\n",copy.id, copy.name, copy.score);}// 5. 清理资源// 注意:原始数据的动态内存需要手动释放(变体内部的由destroy处理)free(original.name);  // 释放原始数据的namecvariant_destroy(var);  // 变体销毁时会自动调用dynamicdata_destroyreturn 0;
}

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

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

相关文章

GraphRAG查询(Query)流程实现原理分析

文章目录说明一 GraphRAG查询&#xff08;Query&#xff09;流程二 Local Search 实现原理三 Global Search 实现原理四 GraphRAG Python API使用说明 本文学自赋范社区公开课&#xff0c;仅供学习和交流使用&#xff01;本文重在介绍GraphRAG查询流程&#xff0c;有关索引构建…

服务器的安全检测和防御技术

1. 服务器安全风险1.1 不必要的访问&#xff08;如只提供HTTP服务&#xff09;若服务器仅需提供 HTTP 服务&#xff0c;却开放了其他不必要的访问途径&#xff0c;会增加风险。通过应用识别、控制&#xff0c;可精准识别应用类型&#xff0c;限制非必要访问&#xff0c;保障服务…

FileLink:为企业跨网文件传输筑牢安全与效率基石

FileLink&#xff1a;为企业跨网文件传输筑牢安全与效率基石在企业数据往来日益频繁的今天&#xff0c;跨网文件传输的安全性和高效性是企业顺畅运营的关键。传统传输方式在安全防护、系统融合及成本控制上的短板愈发明显&#xff0c;而 FileLink 凭借在这些方面的突出表现&…

java设计模式之开闭原则使用举例

1. 输入法皮肤扩展&#xff08;抽象类实现&#xff09; 场景&#xff1a;用户可为输入法更换不同皮肤&#xff08;如默认皮肤、CSDN皮肤&#xff09;。 实现&#xff1a; 抽象层&#xff1a;定义抽象类AbstractSkin&#xff0c;声明皮肤显示方法。扩展&#xff1a;新增皮肤只需…

Spark Shuffle机制原理

文章目录1.什么是Shuffle?2.Shuffle解决什么问题?3.Shuffle Write与Shuffle Read4.Shuffle的计算需求4.1 计算需求表4.2 partitionby4.3 groupByKey4.4 reduceByKey4.5 sortByKey5.Shuffle Write框架设计与实现5.1 Shuffle Write框架实现的功能5.2 Shuffle Write的多种情况5.…

Cursor vs Trae vs VSCode:2025终极IDE横评,谁才是开发者的效率之选?

前言 2025年的编程世界&#xff0c;AI不再只是辅助&#xff0c;而是编程工作流的核心驱动者。从微软的VSCode 到新锐 Cursor 与国产黑马 Trae &#xff0c;三大 IDE 正在重新定义“人机协作”的边界。本文从架构设计、AI能力、场景适配等维度&#xff0c;带你看透工具本质&…

Vue 安装指定版本依赖包、删除某个依赖包、依赖管理

如何安装指定版本的依赖包安装指定版本&#xff1a;一旦你知道了想要的版本号&#xff0c;比如3.4.0&#xff0c;你可以使用以下命令来安装这个版本的vue-router&#xff1a;npm install vue-router3.4.0 --save这里的^表示安装3.4.0的最新小版本更新&#xff0c;但不会超过主版…

psycopg2 如何验证链接是否有效

在 psycopg2 中&#xff0c;验证数据库连接是否有效&#xff08;即连接是否仍然活跃&#xff09;可以通过以下几种方法实现&#xff1a;1. 使用 conn.closed 属性 psycopg2 的连接对象有一个 closed 属性&#xff0c;可以检查连接是否已关闭&#xff1a; import psycopg2conn …

数据科学与计算-电商双11美妆数据分析

一、项目背景&#xff1a;双 11 美妆数据的价值所在 每年的 “双 11” 购物节都是电商行业的盛宴&#xff0c;而美妆品类作为消费热门领域&#xff0c;蕴含着丰富的用户行为与市场趋势信息。该项目聚焦双 11 期间的美妆电商数据&#xff0c;旨在通过数据分析揭示以下核心问题&…

简单了解MongoDB数据存储

官方文档&#xff1a;MongoDB中文手册|官方文档中文版 | MongoDB-CN-Manual 什么是MongoDB? MongnDB是一个分布式文件存储数据库(或叫文档数据库)&#xff0c;是一个介于 关系数据库和非关系数据库之间的产品&#xff0c;是非关系数据库当中功能最丰富&#xff0c;最像关系数…

web网站开发,在线%射击比赛成绩管理%系统开发demo,基于html,css,jquery,python,django,model,orm,mysql数据库

经验心得 这个也是crud业务单子&#xff0c;第二个聊点其他的&#xff0c;从最早的无分层开发&#xff0c;到三层开发&#xff0c;工厂&#xff0c;各种接口&#xff0c;再到后面多层&#xff0c;代码无痕aop&#xff0c;各种框架等&#xff0c;都是在方便我们快速打架一个程序…

[QtADS]解析ads.pro

本文来源 &#xff1a; 腾讯元宝subdirs : 子目录TEMPLATE subdirs的作用​​​​核心功能​​&#xff1a;声明当前项目为“多项目管理”模式。Qt 的构建系统&#xff08;qmake&#xff09;会遍历 SUBDIRS中列出的子目录&#xff0c;在每个子目录中寻找 .pro文件并递归构建。…

三方相机问题分析六:【没用相机,诡异的手电筒不可使用】下拉状态栏,手电筒置灰,无法打开,提提示相机正在使用

【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 三方相机问题分析六:【没用相机,诡异的手电筒不可使用】下拉状态栏,点击手电筒,手电筒置灰,无法打开,提提示相机正在使用9348353 目录 一、问题背景 二、:问题分析过程 2.1:基于…

Java Selenium 自动打开浏览器保存截图

// 代码 public class ScreenshotExample {public static void main(String[] args) {// 1. 设置浏览器驱动路径&#xff08;根据实际路径修改&#xff09;System.setProperty("webdriver.chrome.driver", "D:\\chromedriver-win64\\chromedriver.exe");//…

新商机:为了减少辐射,可以用座机打机房中心再转手机

某些人痛恨自家附近有基站&#xff0c;说是辐射太大。你不能说人家迷信。一般解决办法就是拆基站。而我觉得&#xff0c;商机来了。现在座机基本没人装了。新商机就是座机。附近没有基站&#xff0c;又要打电话&#xff0c;怎么办&#xff1f;装座机。用座机打电话时&#xff0…

【Java|第十九篇】面向对象九——String类和枚举类

&#xff08;四&#xff09;面向对象11、String类&#xff08;1&#xff09;概述<1>String是一个类&#xff0c;引用数据类型&#xff0c;用来表示字符串&#xff1b;<2>String是Lang包下的类&#xff0c;使用不需要导包&#xff1b;<3>字符串的值不能变&…

超越相似名称:Elasticsearch semantic text 如何在简洁、高效、集成方面超越 OpenSearch semantic 字段

作者&#xff1a;来自 Elastic Mike Pellegrini, Nick Chow 及 Libby Lin 比较 Elasticsearch 语义文本和 OpenSearch 语义字段在简洁性、可配置性和效率方面的表现。 自己动手体验向量搜索&#xff0c;使用这个自定进度的 Search AI 实操学习。你现在可以开始免费的云试用&am…

OpenAI发布最新大模型GPT5、本地部署GPT开源模型

OpenAI发布最新大模型GPT5、本地部署GPT开源模型 GPT-5概述 北京时间 2025年8月8日 凌晨1点 OPENAI举行了1个小时的线上发布会&#xff0c;正式推出了其史上最聪明、最强大的大模型GPT-5。 GPT-5是OpenAI发布的最新一代大型语言模型&#xff0c;它基于Transformer架构&#xff…

容器网络模式选择在云服务器多节点部署中的连通性验证方案

容器网络模式选择在云服务器多节点部署中的连通性验证方案在云计算环境中&#xff0c;容器网络模式的选择直接影响着多节点部署的通信效率和安全性。本文将从Docker原生网络驱动对比入手&#xff0c;深入分析Overlay、Host、Bridge等主流网络模式在跨主机通信场景下的性能表现&…

电商双11美妆数据分析

1、数据初步了解2.数据清洗2.1 重复值处理 直接删除重复值。2.2 缺失值处理通过上面观察数据发现sale_count,comment_count 存在缺失值,先观察存在缺失值的行的基本情况存在的缺失值很可能意味着售出的数量为0或者评论的数量为0&#xff0c;所以我们用0来填补缺失值。2.3 数据挖…