java – 使用Jackson令牌流的JSON(> 1演出)中的长字符串
发布时间:2020-12-15 02:09:37 所属栏目:Java 来源:网络整理
导读:我正在尝试编写一些代码处理 JSON文档,其中包含存储在文件中的极长字符串值(超过10亿个字符).我不想将整个字符串保留在内存中(因为我可以在流中处理它们).但我在Jackson解析器中找不到这样的选项.到目前为止我所做的是使用Jackson令牌偏移(第一轮阅读文件)和
我正在尝试编写一些代码处理
JSON文档,其中包含存储在文件中的极长字符串值(超过10亿个字符).我不想将整个字符串保留在内存中(因为我可以在流中处理它们).但我在Jackson解析器中找不到这样的选项.到目前为止我所做的是使用Jackson令牌偏移(第一轮阅读文件)和随机访问文件来处理流中的字符串(第二轮阅读文件):
import java.io.ByteArrayOutputStream; import java.io.File; import java.io.OutputStream; import java.io.PrintWriter; import java.io.RandomAccessFile; import java.nio.charset.Charset; import java.util.HashMap; import java.util.Map; import com.fasterxml.jackson.core.JsonFactory; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; import com.fasterxml.jackson.databind.MappingJsonFactory; public class LongStringJsonTest { public static void main(String[] args) throws Exception { File tempJson = new File("temp.json"); PrintWriter pw = new PrintWriter(tempJson); pw.print("{"k1": {"k11": ""); for (int i = 0; i < 1e8; i++) pw.print("abcdefghij"); pw.print(""},"k2": "klmnopqrst"," + ""k3": ["uvwxyz","0123"]}"); pw.close(); searchForStrings(tempJson); } private static void searchForStrings(File tempJson) throws Exception { JsonFactory f = new MappingJsonFactory(); JsonParser jp = f.createParser(tempJson); Map<Long,Long> stringStartToNext = new HashMap<Long,Long>(); long lastStringStart = -1; boolean wasFieldBeforeString = false; while (true) { JsonToken token = jp.nextToken(); if (token == null) break; if (lastStringStart >= 0) { stringStartToNext.put(lastStringStart,(wasFieldBeforeString ? -1 : 1) * jp.getTokenLocation().getByteOffset()); lastStringStart = -1; wasFieldBeforeString = false; } if (token == JsonToken.FIELD_NAME) { wasFieldBeforeString = true; } else if (token == JsonToken.VALUE_STRING) { lastStringStart = jp.getTokenLocation().getByteOffset(); } else { wasFieldBeforeString = false; } } jp.close(); jp = f.createParser(tempJson); RandomAccessFile raf = new RandomAccessFile(tempJson,"r"); while (true) { JsonToken token = jp.nextToken(); if (token == null) break; if (token == JsonToken.VALUE_STRING) { long start = jp.getTokenLocation().getByteOffset(); long end = stringStartToNext.get(start); // You are able to process stream without keeping all bytes in memory. // Here you see strings including quotes around them. final long[] length = new long[] {0}; ByteArrayOutputStream baos = new ByteArrayOutputStream(); OutputStream os = new OutputStream() { @Override public void write(int b) throws IOException { throw new IOException("Method is not supported"); } @Override public void write(byte[] b,int off,int len) throws IOException { if (baos.size() < 20) { baos.write(b,off,Math.min(len,20)); baos.write((int)'.'); baos.write((int)'.'); baos.write((int)'.'); } if (len > 0) length[0] += len; } }; processString(raf,start,end,os); String text = new String(baos.toByteArray(),Charset.forName("utf-8")); System.out.println("String: " + text + ",length=" + length[0]); } } jp.close(); raf.close(); } private static void processString(RandomAccessFile raf,long start,long end,OutputStream os) throws Exception { boolean wasFieldBeforeString = end < 0; int quoteNum = wasFieldBeforeString ? 3 : 1; end = Math.abs(end); byte[] buffer = new byte[10000]; raf.seek(start); boolean afterBackSlash = false; int strLen = (int)(end - start); for (int chunk = 0; strLen > 0; chunk++) { int ret = raf.read(buffer,Math.min(buffer.length,strLen)); if (ret < 0) break; if (ret > 0) { int offset = 0; if (chunk == 0) { // Assumption that key string doesn't contain double quotes // and it's shorter than buffer size (for simplicity) for (int n = 0; n < quoteNum; n++) { while (true) { if (buffer[offset] == '"' && !afterBackSlash) { break; } else if (buffer[offset] == '') { afterBackSlash = !afterBackSlash; } else { afterBackSlash = false; } offset++; } offset++; } offset--; ret -= offset; } // Searching for ending quote int endQuotePos = offset + (chunk == 0 ? 1 : 0); // Skip open quote while (endQuotePos < offset + ret) { if (buffer[endQuotePos] == '"' && !afterBackSlash) { break; } else if (buffer[endQuotePos] == '') { afterBackSlash = !afterBackSlash; } else { afterBackSlash = false; } endQuotePos++; } if (endQuotePos < offset + ret) { os.write(buffer,offset,endQuotePos + 1 - offset); break; } os.write(buffer,ret); strLen -= ret; } } } } 这种方法根本不支持unicode.我很好奇有没有办法做得更好(或者甚至在其他一些libs的帮助下)? 解决方法
我想你问的是错误的问题.
JSON,如XML或CSV,或任何其他结构化文本表示,有三个主要角色:使数据结构人为可解析,允许通用工具处理许多不同类型的数据,并促进可能使用不同内部的系统之间的数据交换楷模. 如果您不需要这些特定的特征,结构化文本可能是错误的解决方案.专用二进制表示可以更有效,并且随着数据的大小/复杂性增加,该差异可能变得巨大. 支持结构化文本格式,以便导入和导出工具.但是,在内部,您可能应该使用专门针对特定任务需求而调整的数据模型. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
相关内容
- Runtime和ProcessBuilder的替代品(Java)
- java – 如何更新AWS DynamoDB文档API上的地图或列表?
- java语言实现权重随机算法完整实例
- java – 谷歌地图v2 Projection.toScreenLocation(…)非常慢
- java – 推论ArrayIsSredredDirectly直接规则的PMD
- java – 事务性保存而不调用update方法
- java – Smack 4在连接上抛出“SSLHandshakeException:Val
- Java 调用系统系统可执行文件
- 68.26-95.44-99.74 rule|empirical rule
- java – Zoomable JScrollPane – setViewPosition无法更新