如何解析超出内存的JSON?能否用Nlohmann/标准库实现指定索引读取?
处理超大型JSON多维数组的内存友好方案(仅用Nlohmann JSON或标准库)
用Nlohmann JSON实现:SAX流式解析
Nlohmann JSON支持SAX风格的事件驱动解析,无需加载整个JSON到内存,可精准提取指定索引区间的数组元素。核心思路是自定义SAX处理器,跟踪数组层级和当前元素索引,仅在索引落在目标区间时解析并保存元素。
示例代码
#include <nlohmann/json.hpp> #include <fstream> #include <vector> using json = nlohmann::json; class ArrayRangeExtractor : public json::sax_parser { public: ArrayRangeExtractor(size_t start, size_t end) : target_start(start), target_end(end), current_array_level(0), current_element_idx(0) {} bool start_array() override { current_array_level++; if (current_array_level == 1) { current_element_idx = 0; } return true; } bool end_array() override { current_array_level--; return true; } bool start_object() override { if (is_target_element()) { temp_element = json::object(); return true; } return false; } bool end_object() override { if (is_target_element()) { result.push_back(std::move(temp_element)); current_element_idx++; return true; } return false; } bool start_array_element() override { if (is_target_element()) { temp_element = json::array(); return true; } return false; } bool end_array_element() override { if (is_target_element()) { result.push_back(std::move(temp_element)); current_element_idx++; return true; } return false; } bool string(std::string&& s) override { if (is_target_element()) { result.push_back(std::move(s)); current_element_idx++; } return true; } bool number_integer(long long i) override { if (is_target_element()) { result.push_back(i); current_element_idx++; } return true; } std::vector<json> get_result() { return std::move(result); } private: bool is_target_element() { return current_array_level == 1 && current_element_idx >= target_start && current_element_idx <= target_end; } size_t target_start; size_t target_end; size_t current_array_level; size_t current_element_idx; std::vector<json> result; json temp_element; }; int main() { std::ifstream large_json("large_array.json"); ArrayRangeExtractor extractor(1000, 2000); // 提取索引1000到2000的元素 json::sax_parse(large_json, &extractor); auto target_elements = extractor.get_result(); // 处理提取到的元素 return 0; }
说明
- 处理器仅跟踪最外层数组的元素索引,非目标元素的内部结构会直接跳过,不会占用额外内存。
- 需根据实际JSON元素类型,补充重写对应的SAX方法(如
number_float、boolean等)。
用C++标准库实现:手动流式解析
不依赖第三方库时,可直接用标准库文件流手动解析JSON结构,跳过不需要的元素,仅读取目标区间内容。核心是处理嵌套结构和转义字符,准确识别元素边界。
示例代码
#include <fstream> #include <vector> #include <string> #include <cctype> void skip_whitespace(std::ifstream& in) { char c; while (in.get(c) && std::isspace(c)); in.putback(c); } size_t find_element_end(const std::string& content, size_t start) { size_t pos = start; int nested = 0; bool in_string = false; char prev = '\0'; while (pos < content.size()) { char c = content[pos]; if (in_string) { if (c == '"' && prev != '\\') in_string = false; } else { if (c == '"') in_string = true; else if (c == '[' || c == '{') nested++; else if (c == ']' || c == '}') { if (nested == 0) break; nested--; } else if (c == ',' && nested == 0) break; } prev = c; pos++; } return pos; } std::vector<std::string> extract_array_range(std::ifstream& in, size_t start_idx, size_t end_idx) { std::vector<std::string> result; skip_whitespace(in); char c; in.get(c); if (c != '[') return result; size_t current_idx = 0; while (true) { skip_whitespace(in); in.get(c); in.putback(c); if (c == ']') break; std::string element_content; char temp; while (in.get(temp)) { element_content += temp; size_t end_pos = find_element_end(element_content, 0); if (end_pos < element_content.size()) { std::string remaining = element_content.substr(end_pos); for (auto it = remaining.rbegin(); it != remaining.rend(); ++it) in.putback(*it); element_content = element_content.substr(0, end_pos); break; } } if (current_idx >= start_idx && current_idx <= end_idx) { result.push_back(element_content); } if (current_idx > end_idx) break; current_idx++; skip_whitespace(in); in.get(c); if (c != ',') in.putback(c); } return result; } int main() { std::ifstream large_json("large_array.json"); auto target_elements = extract_array_range(large_json, 1000, 2000); for (const auto& elem_str : target_elements) { json elem = json::parse(elem_str); // 处理元素 } return 0; }
说明
- 通过逐字符读取文件,手动跟踪JSON嵌套结构和字符串转义,准确识别每个元素边界。
- 仅保存目标区间的元素字符串,后续可按需解析成JSON对象,内存消耗仅取决于目标元素数量。
内容的提问来源于stack exchange,提问作者Kevin
相关产品推荐
相关产品推荐

