StAX parser解析大文件时字符偏移量溢出的替代方案有哪些
StAX大文件偏移量溢出解决方案
问题原因
JDK原生StAX的Location.getCharacterOffset()返回值为int类型,最大值仅为2147483647,当文件字符数超过该值时就会发生整数溢出,返回负数,无法适配千万行级以上的大文件解析场景。
方案1:自定义Reader自行统计字符偏移量
该方案无需替换依赖、无需修改核心解析逻辑,兼容性最高。你可以自行实现一个包装类,在字符读取时用long类型累计偏移量,全程不会溢出。
自定义CountingReader实现:
import java.io.IOException; import java.io.Reader; public class CountingReader extends Reader { private final Reader delegate; private long charCount = 0; public CountingReader(Reader delegate) { this.delegate = delegate; } @Override public int read(char[] cbuf, int off, int len) throws IOException { int readNum = delegate.read(cbuf, off, len); if (readNum > 0) { charCount += readNum; } return readNum; } @Override public void close() throws IOException { delegate.close(); } // 返回long类型的字符偏移量,无溢出问题 public long getCharacterOffset() { return charCount; } }
改造后的解析代码:
// 用自定义CountingReader包装原始文件输入 CountingReader countingReader = new CountingReader(new FileReader("目标大文件路径")); XMLInputFactory factory = XMLInputFactory.newInstance(); XMLEventReader reader = factory.createXMLEventReader(countingReader); long endOffset = 0; while (reader.hasNext()) { var event = reader.nextEvent(); if (event.isEndElement()) { var endElement = event.asEndElement(); if (endElement.getName().getLocalPart().equals(tag)) { // 直接读取自定义统计的偏移量 endOffset = countingReader.getCharacterOffset(); break; } } }
方案2:切换到支持long型偏移的StAX实现(Woodstox)
Woodstox是高性能开源StAX实现,原生提供long类型的偏移量获取接口,无需自行封装统计逻辑。
首先添加Maven依赖:
<dependency> <groupId>com.fasterxml.woodstox</groupId> <artifactId>woodstox-core</artifactId> <version>6.5.1</version> </dependency>
改造后的解析代码:
import com.ctc.wstx.api.WstxInputFactory; import com.ctc.wstx.api.WstxLocation; // 初始化Woodstox的解析工厂 XMLInputFactory factory = new WstxInputFactory(); XMLEventReader reader = factory.createXMLEventReader(new FileReader("目标大文件路径")); long endOffset = 0; while (reader.hasNext()) { var event = reader.nextEvent(); if (event.isEndElement()) { var endElement = event.asEndElement(); if (endElement.getName().getLocalPart().equals(tag)) { // 转型为Woodstox专用Location接口,获取long型偏移量 WstxLocation location = (WstxLocation) endElement.getLocation(); endOffset = location.getCharacterOffsetLong(); break; } } }
方案3:行号+行内偏移组合计算
如果文件换行符格式固定,也可以用原生API返回的行号、列号组合计算偏移量:5000万行远低于int的上限(2147483647),不会出现行号溢出问题。
注意:需要提前确认文件换行符为
\n(占1字符)还是\r\n(占2字符),计算时要对应调整换行符的总长度。
示例代码:
// 根据实际换行符类型设置,\n填1,\r\n填2 final int NEW_LINE_CHAR_LENGTH = 1; long endOffset = 0; while (reader.hasNext()) { var event = reader.nextEvent(); if (event.isEndElement()) { var endElement = event.asEndElement(); if (endElement.getName().getLocalPart().equals(tag)) { var loc = endElement.getLocation(); // 行号从1开始计数,前面共有(loc.getLineNumber() - 1)个换行符 endOffset = (long) (loc.getLineNumber() - 1) * NEW_LINE_CHAR_LENGTH + loc.getColumnNumber(); break; } } }
内容的提问来源于stack exchange,提问作者pasha
相关产品推荐
相关产品推荐

