You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中将含10k独立JSON对象的文档转为数组及转义问题处理

问题描述

将非SQL源数据库迁移至SQL数据库时,源输出的JSON文档由一系列独立JSON对象组成。使用Java的JSONObject时,它只能识别顶层对象,因此需要编写代码将这些独立对象转为数组。

当前做法是把JSON文档转成字符串,通过计数大括号定位每个对象并插入数组,代码如下:

for (int i = 0; i < doc.length(); i++) {
 char currentChar = doc.charAt(i);
 if (currentChar == '{') {
  Integer jsonStart = i;
  Integer openBrace = 1;
  Integer closeBrace = 0;
  while (openBrace > closeBrace) {
   i++;
   currentChar = doc.charAt(i);
   if (currentChar == '{') {
    openBrace++;
   }
   if (currentChar == '}') {
    closeBrace++;
   }
  }
  Integer jsonEnd = i;
  String currentString = doc.substring(jsonStart, jsonEnd + 1);
  JSONObject currentJSONObject = new JSONObject(currentString);
  returnJSONArray.put(currentJSONObject);
 }
}

因为数据量较大,数据库被拆成多个含10k对象的文档。代码原本运行正常,但遇到值中包含大括号的文档时出错,于是添加代码识别引号包裹的值并忽略其中的大括号:

if (currentChar == '"') {
 i++;
 currentChar = mongoExport.charAt(i);
 while (!(currentChar == '"')) {
  i++;
  currentChar = mongoExport.charAt(i);
 }
}

修改后解决了值含大括号的问题,但测试其他文档时出现**"String index out of range: 大数"**错误,根源是查找结束引号的while循环遇到了转义引号(\"),导致循环一直找不到结束引号,最终超出字符串长度。尝试检查引号前的转义字符但无效,且无法手动检查超长文档,请问如何处理这类字符串?是否有更简便的初始方法?


解决方案
  • 放弃手动解析JSON,使用成熟库:手动处理JSON的字符转义、嵌套结构等场景极易踩坑,转义引号、嵌套对象/数组、Unicode转义等情况都会让手写逻辑漏洞百出。直接用Jackson、Gson这类主流JSON解析库处理这种"JSON Lines"格式的文档,是最稳妥的方案。

  • 用Jackson流式处理JSON Lines:
    你的场景属于标准的JSON Lines格式(每个独立JSON对象占一行或连续排列),Jackson支持流式解析,无需将整个文档加载到内存,适合处理大体积文档。示例代码:

    import com.fasterxml.jackson.databind.ObjectMapper;
    import java.io.File;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;
    
    public class JsonLinesParser {
        public static void main(String[] args) throws IOException {
            ObjectMapper objectMapper = new ObjectMapper();
            File jsonFile = new File("your-input-file.json");
            List<Object> jsonObjects = new ArrayList<>();
    
            // 逐对象解析,内存占用低
            try (var reader = objectMapper.readerFor(Object.class).readValues(jsonFile)) {
                while (reader.hasNext()) {
                    Object jsonObj = reader.next();
                    jsonObjects.add(jsonObj);
                    // 可直接在此处将对象写入SQL数据库,无需先存数组
                }
            }
        }
    }
    
  • 若必须使用org.json的JSONObject:
    可以先将文档拼接成合法的JSON数组字符串再解析,前提是文档中对象以换行分隔或无多余空格:

    import org.json.JSONArray;
    import java.io.BufferedReader;
    import java.io.FileReader;
    import java.io.IOException;
    
    public class JsonToArray {
        public static void main(String[] args) throws IOException {
            StringBuilder sb = new StringBuilder("[");
            try (BufferedReader br = new BufferedReader(new FileReader("your-input-file.json"))) {
                String line;
                boolean isFirst = true;
                while ((line = br.readLine()) != null) {
                    line = line.trim();
                    if (line.isEmpty()) continue;
                    if (!isFirst) sb.append(",");
                    sb.append(line);
                    isFirst = false;
                }
            }
            sb.append("]");
            JSONArray jsonArray = new JSONArray(sb.toString());
            // 后续处理数组中的JSONObject
        }
    }
    

    若文档中对象是连续无换行的{...}{...}格式,这种方式不适用,还是得用流式解析库。

  • 修复现有代码的转义引号判断逻辑:
    若一定要维护现有代码,需正确判断引号是否被转义(连续偶数个反斜杠才是有效转义),修改后的引号处理逻辑:

    if (currentChar == '"') {
        i++;
        while (i < doc.length()) {
            currentChar = doc.charAt(i);
            if (currentChar == '"') {
                // 统计前导反斜杠数量,判断是否为转义引号
                int backslashCount = 0;
                int j = i - 1;
                while (j >= 0 && doc.charAt(j) == '\\') {
                    backslashCount++;
                    j--;
                }
                // 偶数个反斜杠表示当前是结束引号
                if (backslashCount % 2 == 0) break;
            }
            i++;
        }
    }
    

    但这种方式仍无法覆盖所有JSON边界场景,远不如使用现成库可靠。

内容的提问来源于stack exchange,提问作者ZenubisSpyke

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 15:10:42