如何创建与文件大小一致的缓冲区,将命令行传入的.json文件加载到缓冲区?
基于ArenaAllocator动态加载JSON文件的实现方案
用动态扩容的Arena分配器加载JSON文件的核心逻辑是先获取文件大小做初始分配,再按块增量扩容处理边界场景,既避免固定缓冲区的溢出/浪费问题,也充分发挥Arena分配器批量分配、批量释放的优势。以下是可直接落地的C语言实现方案,C++场景可直接对应标准库接口改造。
1. 命令行参数校验
首先校验传入的文件路径参数合法性:
int main(int argc, char** argv) { if (argc < 2) { fprintf(stderr, "用法: %s <目标json文件路径>\n", argv[0]); return 1; } const char* json_path = argv[1]; // 后续逻辑 }
2. Arena分配器基础实现
初始块大小默认设置为4KB(和操作系统页大小对齐,减少内存碎片),不足时自动倍增扩容:
// Arena基础结构定义 typedef struct Arena { char* buf; size_t len; // 已使用长度 size_t capacity; // 总容量 } Arena; // 初始化Arena Arena arena_init(size_t init_cap) { Arena a = {0}; a.buf = malloc(init_cap); if (a.buf) a.capacity = init_cap; return a; } // 扩容逻辑,按需要扩容到能容纳新增数据的大小 void arena_grow(Arena* a, size_t need_size) { size_t new_cap = a->capacity * 2; while (new_cap < a->len + need_size) new_cap *= 2; a->buf = realloc(a->buf, new_cap); a->capacity = new_cap; }
3. JSON文件加载逻辑
优先读取文件总大小做预分配,减少扩容次数;如果是管道等无法获取大小的输入源,自动走逐块读取动态扩容逻辑:
size_t read_json_to_arena(Arena* a, const char* path) { FILE* f = fopen(path, "rb"); if (!f) return 0; // 尝试获取文件总大小,做预分配 fseek(f, 0, SEEK_END); long file_size = ftell(f); fseek(f, 0, SEEK_SET); if (file_size > 0 && a->capacity < file_size) { arena_grow(a, file_size - a->capacity); } // 逐块读取到Arena缓冲区 size_t read_bytes; while ((read_bytes = fread(a->buf + a->len, 1, a->capacity - a->len, f)) > 0) { a->len += read_bytes; // 缓冲区满时自动扩容 if (a->len == a->capacity) { arena_grow(a, 4096); } } // 末尾补'\0',兼容绝大多数字符串形式的JSON解析库 if (a->len < a->capacity) { a->buf[a->len] = '\0'; } else { arena_grow(a, 1); a->buf[a->len] = '\0'; } fclose(f); return a->len; }
4. 调用示例与资源释放
int main(int argc, char** argv) { // 参数校验逻辑省略 Arena a = arena_init(4096); size_t json_len = read_json_to_arena(&a, argv[1]); if (json_len == 0) { fprintf(stderr, "读取JSON文件失败\n"); free(a.buf); return 1; } // 此处直接调用JSON解析库处理a.buf即可,比如cJSON、yyjson等 // 统一释放Arena整块内存,不需要逐块管理分配的内存 free(a.buf); return 0; }
注意事项
- 如果使用C++的标准库分配器,可以直接用
std::pmr::monotonic_buffer_resource作为标准Arena实现,不需要自己手写分配逻辑,配合std::pmr::string存储JSON内容即可,代码更简洁。 - 处理不可信来源的文件时,可以设置Arena的最大容量阈值,避免恶意超大文件占满内存。
- 读取二进制JSON格式(UBJSON/BSON)时不需要补末尾的
\0,直接保留原始字节即可。
内容的提问来源于stack exchange,提问作者dxbednarczyk
相关产品推荐
相关产品推荐

