背景:
当从API获取数据或与其他系统交换信息时。有时json字符串可能会非常庞大,以至于读取到内存中会导致内存溢出或者性能问题
流式处理:
如果JSON字符串过大,不适合一次性加载到内存中,可以考虑使用流式处理。例如,使用Jackson库的JsonParser,可以逐行解析JSON,从而避免一次性加载整个字符串。
一般大json中都会存在某个数组中有超多的数据记录,我们需要解决的就是记录当前token路径,在读取到超大json数组时,再利用逐条数据读取mapper.readTree(jsonParser)逐条读取数据,利用数组缓存一定量的数据后,写入数据库后继续读取,直到json数组数据读取结束
ObjectMapper mapper = new ObjectMapper();
JsonParser parser = mapper.getFactory().createParser(jsonStream);
|
JsonParser
进行解析的大致流程如下:
- 从头开始扫描
JSON
字符串
- 依次识别每个
JSON
组成元素
- 解析到结束位置,关闭解析器
分块读取:
如果从网络或文件中读取JSON,可以使用缓冲区分块读取,而不是一次性读取整个文件。例如,使用Java NIO的BufferedReader。
Path path = Paths.get("large.json");
StringBuilder jsonBuilder = new StringBuilder();
try (BufferedReader reader = Files.newBufferedReader(path)) {String line;while ((line = reader.readLine()) != null) {jsonBuilder.append(line).append("\n");}
} catch (IOException e) {e.printStackTrace();
}
String jsonString = jsonBuilder.toString();
|
使用第三方库:
有些库如Gson、Jackson提供了直接从输入流中解析JSON的功能,无需将整个JSON字符串加载到内存中。
InputStream inputStream = new FileInputStream("large.json");
Gson gson = new Gson();
YourModel model = gson.fromJson(inputStream, YourModel.class);
inputStream.close();
|
总结:
处理大型JSON字符串时,要避免一次性加载到内存中,以免造成内存溢出。通过使用StringBuilder、流式处理、分块读取或者借助第三方库,保证性能,又能避免内存问题。
背景:
酒店报价接口,会返回大量结构复杂的json数据,当需要追踪返回数据时非常困难,因此需要有清晰json解析方法
方法设计:
public class HotelTest {@Testpublic void test() throws IOException {//读取resource目录下的.json文件中的几个字段的值// 获取资源文件ClassLoader classLoader = getClass().getClassLoader();InputStream inputStream = classLoader.getResourceAsStream("execption.json");// 读取文件内容ObjectMapper objectMapper = new ObjectMapper();JsonNode jsonNode = objectMapper.readTree(inputStream);// 提取所需字段JsonNode nestedNode = jsonNode.path("data").path("rooms");for (JsonNode room : nestedNode) {JsonNode room1 = room.path("rateplans");//通过rateplan判断多个rateplan是不是同质化房型List<SymRoom> symRooms = new ArrayList<>();for (JsonNode rateplan : room1) {//room1是第一个房型的所有报价对象,rateplan是其中一个报价对象String paymentType = rateplan.get("paymentType").asText();String breakfast = rateplan.get("breakfast").asText();String status = rateplan.get("status").asText();String customerType = rateplan.get("customerType").asText();String daysMin = rateplan.get("daysMin").asText();Double totalRate = rateplan.get("totalRate").asDouble();String refundType = rateplan.get("refundType").asText();String refundTime = rateplan.get("refundTime").asText();String refundDesc = rateplan.get("refundDesc").asText();//组装对象SymRoom symRoom = new SymRoom();symRoom.setPaymentType(paymentType);symRoom.setBreakfast(breakfast);symRoom.setStatus(status);symRoom.setCustomerType(customerType);symRoom.setDaysMin(daysMin);symRoom.setTotalRate(totalRate);symRoom.setRefundType(refundType);symRoom.setRefundTime(refundTime);symRoom.setRefundDesc(refundDesc);symRooms.add(symRoom);// 打印提取的字段值System.out.println("paymentType: " + paymentType);System.out.println("breakfast: " + breakfast);System.out.println("status: " + status);System.out.println("customerType: " + customerType);System.out.println("daysMin: " + daysMin);System.out.println("totalRate: " + totalRate);System.out.println("refundType: " + refundType);System.out.println("refundTime: " + refundTime);System.out.println("refundDesc: " + refundDesc);System.out.println("totalRate是否为空:" + Objects.isNull(totalRate));System.out.println("====================================");}}}
}
|