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

Java中如何从JSON文件指定索引开始读取数据?

高效从指定索引开始解析JSON数组的方案

你的问题很典型:当处理百万级别的JSON数组时,全量解析再用subList截取会导致内存占用过高和解析效率低下——毕竟要把所有对象都加载到内存里,完全没必要。解决这个问题的核心是用流式解析,也就是逐个读取JSON元素,跳过前99个,只处理从第100个开始的内容,全程不需要把整个数组加载到内存。

下面给你两种实用的实现方案,分别基于目前最常用的两个JSON库:

方案一:使用Jackson流式API(推荐)

Jackson是Java生态中性能最好的JSON库之一,它的流式API专门为处理大文件设计,内存占用极低。

代码示例

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.FileReader;
import java.io.IOException;

public class JsonStreamProcessor {
    public static void processJsonFromIndex(int startIndex) throws IOException {
        // 初始化Jackson的核心组件
        JsonFactory factory = new JsonFactory();
        ObjectMapper mapper = new ObjectMapper();
        
        // 用try-with-resources自动关闭资源
        try (JsonParser parser = factory.createParser(new FileReader("D:\\2018-4-21.json"))) {
            // 先定位到JSON数组的起始位置
            if (parser.nextToken() != JsonToken.START_ARRAY) {
                throw new IOException("文件内容不是有效的JSON数组");
            }
            
            int currentItemIndex = 0;
            JsonToken currentToken;
            
            while ((currentToken = parser.nextToken()) != null) {
                // 数组结束就退出循环
                if (currentToken == JsonToken.END_ARRAY) {
                    break;
                }
                
                currentItemIndex++;
                // 跳过前99个元素(如果startIndex是100,对应索引0-99的元素)
                if (currentItemIndex < startIndex) {
                    // 直接跳过当前对象的所有子节点,不解析
                    parser.skipChildren();
                    continue;
                }
                
                // 解析当前JSON对象并处理
                JsonNode jsonObject = mapper.readTree(parser);
                // 这里替换成你的业务逻辑,比如获取字段
                String targetField = jsonObject.get("che...").asText();
                System.out.println("处理第" + currentItemIndex + "个对象:" + targetField);
            }
        }
    }

    public static void main(String[] args) throws IOException {
        // 从第100个元素开始处理(注意:这里的索引是从1开始计数,如果你的原代码subList(100, ...)是跳过前100个(索引0-99),这里传100正好对应)
        processJsonFromIndex(100);
    }
}

方案优势

  • 内存占用极小:只在处理当前对象时加载其数据,不会把百万级数组全部塞进内存
  • 解析效率高:跳过不需要的元素时直接跳过子节点,无需解析内容
  • 代码简洁:Jackson的流式API封装得很友好,容易维护

方案二:使用JSON.simple的流式处理(适配你的原有库)

如果你因为项目依赖限制必须使用JSON.simple,也可以通过操作token流来实现跳过逻辑,不过这个库的流式API不够完善,代码会繁琐一些。

代码示例

import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.json.simple.parser.Token;
import org.json.simple.parser.TokenType;
import org.json.simple.parser.Yylex;

import java.io.FileReader;
import java.io.IOException;

public class JsonSimpleStreamProcessor {
    public static void processJsonFromIndex(int startIndex) throws IOException, ParseException {
        JSONParser parser = new JSONParser();
        try (FileReader reader = new FileReader("D:\\2018-4-21.json")) {
            Yylex lexer = new Yylex(reader);
            Token currentToken;
            
            // 先定位到JSON数组的左括号
            while ((currentToken = lexer.nextToken()) != null) {
                if (currentToken.type == TokenType.LEFT_BRACKET) {
                    break;
                }
            }
            
            int currentItemIndex = 0;
            while ((currentToken = lexer.nextToken()) != null) {
                // 数组结束就退出
                if (currentToken.type == TokenType.RIGHT_BRACKET) {
                    break;
                }
                
                currentItemIndex++;
                if (currentItemIndex < startIndex) {
                    // 跳过当前对象:需要计数大括号,直到匹配到闭合的右括号
                    int braceCount = 1;
                    while ((currentToken = lexer.nextToken()) != null) {
                        if (currentToken.type == TokenType.LEFT_BRACE) {
                            braceCount++;
                        } else if (currentToken.type == TokenType.RIGHT_BRACE) {
                            braceCount--;
                            if (braceCount == 0) {
                                break;
                            }
                        }
                    }
                    continue;
                }
                
                // 解析当前对象并处理
                JSONObject jsonObject = (JSONObject) parser.parse(lexer);
                String targetField = (String) jsonObject.get("che...");
                System.out.println("处理第" + currentItemIndex + "个对象:" + targetField);
            }
        }
    }

    public static void main(String[] args) throws IOException, ParseException {
        processJsonFromIndex(100);
    }
}

注意事项

JSON.simple的token处理需要自己手动计数大括号,容易出错,而且解析效率不如Jackson,所以优先推荐方案一。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:18:49