【问题标题】:How do you trick SAX into breaking large chunks into smaller chunks in java?你如何欺骗 SAX 在 Java 中将大块分成更小的块?
【发布时间】:2015-04-30 16:52:17
【问题描述】:

我正在覆盖

public void characters(char[] ch,
                       int start,
                       int length)
                throws SAXException

在解析 XML 文档时。它非常适用于小型 XML 文档(1MB 或更少)。但是,如果 XML 文档为 100MB 或更多),我开始在此函数中获取 java 堆空间不足内存错误。

在做了一些研究here 之后,我意识到上面的字符数组 "ch" 的大小取决于 "startElement()" 和 "endElement()" 之间有多少个字符。

所以我想知道,是否有一种聪明的方法来覆盖“startElement”和“endElement”以返回更小的数据块?

例如,假设我有一个如下所示的 XML 文件:

<element1>
   This is a very simple sentence that is not very long. 
</element1>

目前“characters()”函数会返回“这是一个非常简单的句子,不是很长。”作为一个块。

但我的问题是,如果 XML 文件看起来像这样:

<element1>
   An entire book's worth of content is pasted in this single element. Possibly millions of characters.  
</element1>

有没有办法我可以“欺骗” startElement() 和 endElement() 让 characters() 函数返回整本书中的书块?

【问题讨论】:

  • 100 MiB 不算多...愿意展示您的代码吗?
  • 其实我以为java sax解析器已经默认做到了?
  • 你使用的是标准的java解析器,还是第三方实现的?
  • 这里的问题不太可能是 SAX 解析器配置,更可能是字符方法实现不充分。 OP 没有展示任何关于如何正确使用字符方法的意识,并且不包括minimal reproducible example。以 OffTopic/no mcve 投票结束。

标签: java xml sax


【解决方案1】:

您不能欺骗 SAX 解析器以较小的块将字符数据提供给您的ContentHandler。然而,解析器已经被允许以比元素的全部内容更小的块来提供它,我希望这是它们在内容很大时的正常行为。否则将要求他们在内部缓冲大量数据,没有特别的原因。

如果您发现您的特定解析器确实提供了比您想要的更大的块,那么您应该查阅它的文档。您可以设置一个选项来影响它。否则,您的替代方法是找到或制作一个您更喜欢其行为的解析器。

但是,请检查您的事实。可能是解析器确实以合理大小的块返回数据,问题实际上出在你对它们所做的事情上。特别是,如果您正在构建整个文件的某种内存表示形式,那么您收到的文件大小无关紧要。

还可以考虑增加 VM 的最大堆大小。 100MB 的文件并不算大,但您的虚拟机可能会受到堆大小限制的困扰,该限制对于该问题来说是不切实际的低。

【讨论】:

    【解决方案2】:

    非常老的线程,但最近我不得不处理类似的任务,所以发布我的答案可能对其他人有用。最新的java版本我认为jdk 9具有读取字符数据块的功能,您只需要设置CDATA_CHUNK_SIZE,它在Stax和Sax解析器中都可用。

    import java.io.FileInputStream;
    import java.io.InputStream;
    import javax.xml.parsers.SAXParser;
    import javax.xml.parsers.SAXParserFactory;
    
    import org.xml.sax.InputSource;
    import org.xml.sax.XMLReader;
    
    public class SaxDemo {
    
        final static String CDATA_CHUNK_SIZE = "jdk.xml.cdataChunkSize";
    
        public static void main(String argv[]) {
    
            try {
    
                SAXParserFactory spf = SAXParserFactory.newInstance();
                SAXParser sp = spf.newSAXParser();
    
                XMLReader reader = sp.getXMLReader();
                reader.setContentHandler(new TestHandler());
    
                try (InputStream is = new FileInputStream("FileDir/file")) {
    
                    reader.setProperty(CDATA_CHUNK_SIZE, 10000);
    
                    reader.parse(new InputSource(is));
                    System.out.println("Done");
    
                }
    
            } catch (Exception e) {
                e.printStackTrace();
            }
    
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 2010-10-11
      • 2016-06-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-07
      • 1970-01-01
      • 2022-10-13
      • 2018-11-23
      相关资源
      最近更新 更多