当前位置: 首页 > 面试题库 >

如何在Java中解析大(50 GB)XML文件

胡鸿禧
2023-03-14
问题内容

目前,我正在尝试使用SAX解析器,但是通过文件它大约3/4完全冻结了,我尝试分配更多的内存等,但没有得到任何改善。

有什么办法可以加快速度吗?更好的方法?

剥开它的骨头,所以我现在有了以下代码,并且在命令行中运行时,它的运行速度还没有达到我想要的速度。

使用“ java -Xms-4096m -Xmx8192m -jar reader.jar”运行它,得到的GC开销限制超出了文章700000

主要:

public class Read {
    public static void main(String[] args) {       
       pages = XMLManager.getPages();
    }
}

XML管理器

public class XMLManager {
    public static ArrayList<Page> getPages() {

    ArrayList<Page> pages = null; 
    SAXParserFactory factory = SAXParserFactory.newInstance();

    try {

        SAXParser parser = factory.newSAXParser();
        File file = new File("..\\enwiki-20140811-pages-articles.xml");
        PageHandler pageHandler = new PageHandler();

        parser.parse(file, pageHandler);
        pages = pageHandler.getPages();

    } catch (ParserConfigurationException e) {
        e.printStackTrace();
    } catch (SAXException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }


    return pages;
    }    
}

页面处理程序

public class PageHandler extends DefaultHandler{

    private ArrayList<Page> pages = new ArrayList<>();
    private Page page;
    private StringBuilder stringBuilder;
    private boolean idSet = false;

    public PageHandler(){
        super();
    }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {

        stringBuilder = new StringBuilder();

         if (qName.equals("page")){

            page = new Page();
            idSet = false;

        } else if (qName.equals("redirect")){
             if (page != null){
                 page.setRedirecting(true);
             }
        }
    }

     @Override
     public void endElement(String uri, String localName, String qName) throws SAXException {

         if (page != null && !page.isRedirecting()){

             if (qName.equals("title")){

                 page.setTitle(stringBuilder.toString());

             } else if (qName.equals("id")){

                 if (!idSet){

                     page.setId(Integer.parseInt(stringBuilder.toString()));
                     idSet = true;

                 }

             } else if (qName.equals("text")){

                 String articleText = stringBuilder.toString();

                 articleText = articleText.replaceAll("(?s)<ref(.+?)</ref>", " "); //remove references
                 articleText = articleText.replaceAll("(?s)\\{\\{(.+?)\\}\\}", " "); //remove links underneath headings
                 articleText = articleText.replaceAll("(?s)==See also==.+", " "); //remove everything after see also
                 articleText = articleText.replaceAll("\\|", " "); //Separate multiple links
                 articleText = articleText.replaceAll("\\n", " "); //remove new lines
                 articleText = articleText.replaceAll("[^a-zA-Z0-9- \\s]", " "); //remove all non alphanumeric except dashes and spaces
                 articleText = articleText.trim().replaceAll(" +", " "); //convert all multiple spaces to 1 space

                 Pattern pattern = Pattern.compile("([\\S]+\\s*){1,75}"); //get first 75 words of text
                 Matcher matcher = pattern.matcher(articleText);
                 matcher.find();

                 try {
                     page.setSummaryText(matcher.group());
                 } catch (IllegalStateException se){
                     page.setSummaryText("None");
                 }
                 page.setText(articleText);

             } else if (qName.equals("page")){

                 pages.add(page);
                 page = null;

            }
        } else {
            page = null;
        }
     }

     @Override
     public void characters(char[] ch, int start, int length) throws SAXException {
         stringBuilder.append(ch,start, length); 
     }

     public ArrayList<Page> getPages() {
         return pages;
     }
}

问题答案:

您的解析代码可能工作正常,但您正在加载的数据量可能太大而无法保存在其中ArrayList

您需要某种流水线将数据传递到其实际目的地,而不必一次将所有数据都存储在内存中。

我有时针对这种情况所做的工作与以下类似。

创建用于处理单个元素的接口:

public interface PageProcessor {
    void process(Page page);
}

PageHandler通过构造函数将此实现提供给:

public class Read  {
    public static void main(String[] args) {

        XMLManager.load(new PageProcessor() {
            @Override
            public void process(Page page) {
                // Obviously you want to do something other than just printing, 
                // but I don't know what that is...
                System.out.println(page);
           }
        }) ;
    }

}


public class XMLManager {

    public static void load(PageProcessor processor) {
        SAXParserFactory factory = SAXParserFactory.newInstance();

        try {

            SAXParser parser = factory.newSAXParser();
            File file = new File("pages-articles.xml");
            PageHandler pageHandler = new PageHandler(processor);

            parser.parse(file, pageHandler);

        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

将数据发送到此处理器,而不是将其放在列表中:

public class PageHandler extends DefaultHandler {

    private final PageProcessor processor;
    private Page page;
    private StringBuilder stringBuilder;
    private boolean idSet = false;

    public PageHandler(PageProcessor processor) {
        this.processor = processor;
    }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
         //Unchanged from your implementation
    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
         //Unchanged from your implementation
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
            //  Elide code not needing change

            } else if (qName.equals("page")){

                processor.process(page);
                page = null;

            }
        } else {
            page = null;
        }
    }

}

当然,您可以使您的界面处理多条记录而不是仅处理一条记录,并将PageHandler收集页面本地放在较小的列表中,并定期将列表发送出去进行处理并清除列表。

或者(也许更好),您可以实现PageProcessor此处定义的接口,并在其中构建逻辑来缓冲数据并将其发送以进一步进行大块处理。



 类似资料:
  • 问题内容: 我有以下问题: 我有一个XML文件(大约1GB),并且必须上下迭代(即不连续;一个接一个),以便获取所需的数据并对其进行一些操作。最初,我使用了DOM Java包,但是很显然,在解析XML文件时,JVM达到了其最大堆空间并停止了运行。 为了解决这个问题,我想到的解决方案之一是找到另一个解析器,该解析器迭代XML中的每个元素,然后将其内容存储在硬盘上的临时SQLite数据库中。因此,通过

  • 如何在java StaX解析器中读取此xml。这是示例 xml。原始文件大小大于 2 GB。所以只有我去StaX解析器。我的Java类是BulkFileReader.java 我使用此java代码从xml标记中检索值。当我使用这个代码时。我可以检索第三个

  • 我有一个XML文件,如 我需要值,即“OEBPS/content.opf”文本。我尝试使用文档生成器和XML解析器,但没有结果。如何遍历该节点并获取值

  • 本文向大家介绍java如何解析/读取xml文件,包括了java如何解析/读取xml文件的使用技巧和注意事项,需要的朋友参考一下 本文实例为大家分享了java解析/读取xml文件的方法,供大家参考,具体内容如下 XML文件 Java 代码: 以上就是本文的全部内容,希望对大家的学习有所帮助。

  • 问题内容: 我需要解析大小为40GB的XML文件,然后进行规范化,然后插入到MySQL数据库中。我尚不清楚需要在数据库中存储多少文件,我也不知道XML结构。 我应该使用哪个解析器,您将如何进行呢? 问题答案: 在PHP中,您可以使用 Docs 读取超大型XML文件: 特大XML文件应以压缩格式存储在磁盘上。至少这是有道理的,因为XML文件具有很高的压缩率。例如,像gzip一样。 PHP 通过压缩包

  • 问题内容: 我需要一个XML解析器来解析大约1.8 GB的文件。 因此,解析器不应将所有文件加载到内存中。 有什么建议? 问题答案: 除了推荐的SAX解析之外,您还可以使用JDK(包javax.xml.stream)中包含的StAX API(一种SAX演进)。 StAX项目主页:http://stax.codehaus.org/Home 简介:http : //www.xml.com/pub/a/