Problema de estouro de memória com docBuilder.parse

Galera do java, beleza?
Então, estou com um problema com estouro de memoria.java.lang.Exception: Erro na unificação do arquivo: arqnfSP112011
at br.gov.suframa.internamento.fisco.gui.FiscoFileMergerMainFrame$UnificacaoExecutavel.run(FiscoFileMergerMainFrame.java:548)
at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOfRange(Unknown Source)
at java.lang.String.<init>(Unknown Source)
at org.apache.xerces.xni.XMLString.toString(Unknown Source)
at org.apache.xerces.parsers.AbstractDOMParser.characters(Unknown Source)
at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanContent(Unknown Source)
at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source)
at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
at org.apache.xerces.parsers.XML11

Penso ser devido ao metodo docBuilder.parse que consome muita memoria. Alguém conhece algum substituto que faça o trabalho “sujo” sem consumir muita memoria, ou que trabalhe com a memoria do hard disk em vez da RAM.

Thanks.

Por favor, ao postar tópicos não abuse das letras maiúsculas no título. Não tem porque chamar mais atenção que os demais.

Quanto ao seu problema, já experimentou aumentar o tamanho do heap da VM?
Por padrão, o da VM é bem pequeno (algo entre 32 ou 64 mb).

Não foi intenção, chamar a atenção de ninguem, mas deu certo. hehehe.

Então meu caro. Esta questão de aumentar o limite da memo da VM ja faiz e deu certo. Porém, o meu objetivo é realmente diminuir este uso de memória. Conhece alguma forma?

Procure algum parser de XML baseado em StAX:
http://woodstox.codehaus.org/
https://sjsxp.dev.java.net/

Ou escreva diretamente em arquivos. Como isso parece ser um “merger”, não deve ser muito difícil.

Caro.

Tentei usar o SAX e não consegui. Mas vou mais a fundo para resolver o problema com SAX. Quero somente saber ser essa biblioteca tem todas as funcionalidades que a Document.Builder faz.

Eu falei StAX e não SAX.

Opa! Tranquilo?
Estou usando StAX, como indicado. Dei uma lida na doc da sun sobre esta API.

Então, desenvolvi o codigo abaixo. Porém esta me lançando uma Exception:

…função(InputStream input1,
InputStream input2){

XMLEventWriter eventWriter;
XMLEventFactory eventFactory = XMLEventFactory.newInstance();
XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();

		eventWriter = outputFactory
				.createXMLEventWriter(new FileOutputStream(&quot;testMerge1.xml&quot;));

		XMLEvent newLine = eventFactory.createDTD(&quot;\notasfiscais&quot;);

		StartDocument startDocument = eventFactory.createStartDocument();

		eventWriter.add(startDocument);
		eventWriter.add(newLine);

		StartElement configStartElement = eventFactory.createStartElement(
				&quot;&quot;, &quot;&quot;, &quot;TestCaseBlock&quot;);

		eventWriter.add(configStartElement);
		eventWriter.add(newLine);

		InputStream[] filenames = new InputStream[] { input1, input2 };

		for (InputStream filename : filenames) {

			XMLInputFactory factory = XMLInputFactory.newInstance();
			XMLEventReader testEventReader = factory.createXMLEventReader(input1);&lt;&lt;&lt;----[i][b]Aqui está o problema, n entendo o pq, ja que esta variavel input1 ja é uma inputStream criado apartir do XML e me enviado pela função.[/b][/i]

			while (testEventReader.hasNext()) {
				XMLEvent event = testEventReader.nextEvent();
				if (event.getEventType() != XMLEvent.START_DOCUMENT
						&& event.getEventType() != XMLEvent.END_DOCUMENT)
					eventWriter.add(event);
				eventWriter.add(newLine);
				testEventReader.close();
			}

		}

}

E a exception é : javax.xml.stream.XMLStreamException: java.io.IOException: Stream closed
at com.sun.org.apache.xerces.internal.impl.XMLStreamReaderImpl.setInputSource(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLStreamReaderImpl.<init>(Unknown Source)
at com.sun.xml.internal.stream.XMLInputFactoryImpl.getXMLStreamReaderImpl(Unknown Source)
at com.sun.xml.internal.stream.XMLInputFactoryImpl.createXMLStreamReader(Unknown Source)
at com.sun.xml.internal.stream.XMLInputFactoryImpl.createXMLEventReader(Unknown Source)
at br.gov.suframa.internamento.fisco.merger.impl.XMLMerger.merge(XMLMerger.java:121)
at br.gov.suframa.internamento.fisco.merger.impl.XMLMerger.mergeXML(XMLMerger.java:61)
at br.gov.suframa.internamento.fisco.merger.impl.XMLMerger.merge(XMLMerger.java:44)
at br.gov.suframa.internamento.fisco.FiscoFileMerger.executarUnificacao(FiscoFileMerger.java:94)
at br.gov.suframa.internamento.fisco.gui.FiscoFileMergerMainFrame$UnificacaoExecutavel.run(FiscoFileMergerMainFrame.java:552)
at java.lang.Thread.run(Unknown Source)
Caused by: java.io.IOException: Stream closed
at java.io.BufferedInputStream.getBufIfOpen(Unknown Source)
at java.io.BufferedInputStream.fill(Unknown Source)
at java.io.BufferedInputStream.read(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLEntityManager$RewindableInputStream.read(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.startEntity(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.startDocumentEntity(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.setInputSource(Unknown Source)

thanks man.

while (testEventReader.hasNext()) {
    XMLEvent event = testEventReader.nextEvent();
    if (event.getEventType() != XMLEvent.START_DOCUMENT
    && event.getEventType() != XMLEvent.END_DOCUMENT)
        eventWriter.add(event);
    eventWriter.add(newLine);
    testEventReader.close();
} 

Você fechou o testEventReader dentro do loop por quê?

Estou seguindo o padrão da documentação. Mas a implementação nem chega nesta lparte do codigo. Quebra justamente na linha que deixei destacada(linha 121). A exception é em cima dela.

Encontrei meu erro primário. Está no for() . Ja que ele dá 2 voltas, devido ao array filenames[]. Valeu Pessoal.

InputStream[] filenames = new InputStream[] { input1, input2 };

for (InputStream filename : filenames) {

XMLInputFactory factory = XMLInputFactory.newInstance();
XMLEventReader testEventReader = factory.createXMLEventReader(input1);

Acho que você está fazendo um pouco de salada. O correto,no seu caso, provavelmente seria:

InputStream[] inputstreams = new InputStream[] { input1, input2 };

for (InputStream inputstream : inputstreams) {

XMLInputFactory factory = XMLInputFactory.newInstance();
XMLEventReader testEventReader = factory.createXMLEventReader(inputstream);

E de modo geral, que documentação você está seguindo? (poste a URL)
Duvido que na documentação alguém fechasse um EventReader dentro do loop.

De modo geral, o que vc fez foi mudar o nome das variáveis, para nomes mais padronizados.

Nesta questão do close. Eu intendo que o EventReader seria cada linha o tag do xml, e que ele lê este Event, joga para o novo XML criado e fecha a linha, para que na proxima interação, ele pegue a proxima linha. Não sei se estou certo.

Tem como enviar uma sugestão neste caso do loop?

Estou seguindo um cod do stakeoverflow e não como erroneamente eu disse anteriormente.
http://stackoverflow.com/questions/5681597/how-to-merge-two-xmls-in-java

Thanks man.

Ah, o carinha escreveu um código que poderia ser resolvido com um “if”, não com um “while”.

Agora entendi mais ou menos a história do close().

É que normalmente se você faz um “close()” e depois chama “hasNext()”, em vez de o hasNext retornar false, ele dá uma exceção com uma mensagem mais ou menos do tipo “Stream already closed” ou coisa parecida.

De qualquer maneira, usar nomes mais padronizados evita você fazer bagunças como ter se esquecido de trocar o “input1”, naquela linha que deu o problema.

Se você trocou o tipo de String para InputStream, e fez algumas alterações a mais, é aconselhável você também mudar o nome para ficar mais fácil de você acompanhar o que deve ser feito.

E ai pessoal, aqui novamente. O que ma falta agora para finalizar é transformar este meu xml criado que está contido na variavel eventWriter em um inputStream ou ByteArrayInputStream para dar o return da função. Como fazer este cast? Como fazer isso? :?:

Migrei para o StAX, para fazer o merge, esta dando quase tudo certo. Mas estou tendo problemas com a organização das tags de dentro do xml. Outro assunto é a exception que está sendo lançada. Alguem para dar uma força? A unica organização que quero é a da tag principal !

file

… 70mb de arquivos

file1

… 5mb de arquivos

resultado esperado = teste

75mb de arquivos

[code]import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.events.StartDocument;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import javax.xml.stream.XMLInputFactory;

public class main {

public static void main(String[] args) throws FileNotFoundException,
		XMLStreamException {

	// TODO Auto-generated constructor stub


	XMLEventWriter eventWriter = null;
	XMLEventFactory eventFactory = null;
	XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();

	File file = new File("C:/XMLftp.xml");<---- Este arquivo ja existe
	File file1 = new File("C:/XMLLocal.xml");<---- Este arquivo ja existe
	File teste = new File("C:/XMLTESTE.xml");

	if (file.exists() && file1.exists()) {
		System.out.println("Os arquivos existem");
	} else {
		System.out.println("Não existem");

	}

	try {
		teste.createNewFile();
	} catch (IOException e1) {
		// TODO Auto-generated catch block
		e1.printStackTrace();
	}

	eventWriter = outputFactory.createXMLEventWriter(new FileOutputStream(
			teste));
	eventFactory = XMLEventFactory.newInstance();
	


	XMLEvent newLine = eventFactory.createDTD("\n");

	StartDocument startDocument = eventFactory.createStartDocument();

	eventWriter.add(startDocument);
	eventWriter.add(newLine);

	StartElement configStartElement = eventFactory.createStartElement("",
			"", "notasfiscais");

	eventWriter.add(configStartElement);
	eventWriter.add(newLine);

	String[] filenames = new String[] {  "C:/XMLftp.xml" , "C:/XMLLocal.xml"  };

	for (String filename : filenames) {

		FileInputStream inputStream = new FileInputStream(filename);
//InputStream inputReader = new FileInputStream(filename);
		
		XMLInputFactory inputFactory = XMLInputFactory.newInstance();
		
		XMLEventReader test = inputFactory
				.createXMLEventReader(inputStream);
		
		// docBuilderFactory.setNamespaceAware(true);
		// docBuilderFactory.setIgnoringElementContentWhitespace(true);

		int i = 0;
		while (test.hasNext()) {
			XMLEvent event = test.nextEvent();
			
			i++;
			// avoiding start(<?xml version="1.0"?>) and end of the
			// documents;
            
			if (event.getEventType() != XMLEvent.START_DOCUMENT
					&& event.getEventType() != XMLEvent.END_DOCUMENT )
					eventWriter.add(event);
				

			eventWriter.add(newLine);
			test.close();
		}

	}
	eventWriter.add(eventFactory.createEndElement("", "", "notasfiscais"));
//	eventWriter.add(newLine);
	eventWriter.add(eventFactory.createEndDocument());
	eventWriter.close();
}

}[/code]

Exception

Exception in thread "main" javax.xml.stream.XMLStreamException: No element was found to write: java.lang.ArrayIndexOutOfBoundsException: -1 at com.sun.xml.internal.stream.writers.XMLStreamWriterImpl.writeEndElement(Unknown Source) at com.sun.xml.internal.stream.writers.XMLEventWriterImpl.add(Unknown Source) at main.main(main.java:94) Caused by: java.lang.ArrayIndexOutOfBoundsException: -1 at com.sun.xml.internal.stream.writers.XMLStreamWriterImpl$ElementStack.pop(Unknown Source) ... 3 more

Fala galera. Depois de muito trabalho. Final cheguei onde gostaria. Merge usando StAX. Segue abaixo somente a função.
A lógica não é muito direta. Mas foi a forma que encontrei para resolver o problema. :!:

fileFtp:

<?xml version="1.0" encoding="UTF-8"?> <notasfiscais> <notafiscal>fdfdfdfd</notafiscal> <notafiscal>fdsfgsd</notafiscal> </notasfiscais>

fileLocal:

[code]<notasfiscais> <notafiscal>rerer</notafiscal> <notafiscal>saffdsf</notafiscal> </notasfiscais>
[/code]

Obs: É claro que os arquivos principais existem para mais de 300.000 eventos, estes acima são somente para ilustrar.

teste <----- Resultado

<notasfiscais> <notafiscal>fdfdfdfd</notafiscal> <notafiscal>fdsfgsd</notafiscal> <notafiscal>rerer</notafiscal> <notafiscal>saffdsf</notafiscal> </notasfiscais>

[code]import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLOutputFactory;

import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.XMLEvent;
import javax.xml.stream.XMLInputFactory;

public class Teste {

//fileFtp e fileLocal são arquivos XML. Pelo menos o mapeamento dele. E levo em consideração que os dois existem!

public InputStream merge(File fileFtp , File fileLocal) throws FileNotFoundException, XMLStreamException{

	// TODO Auto-generated constructor stub

	XMLEventWriter eventWriter = null;
	XMLEventFactory eventFactory = null;
	XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();

	File teste = new File("C:\\XMLTESTE.xml");

	try {
		teste.createNewFile();
	} catch (IOException e1) {
		// TODO Auto-generated catch block
		e1.printStackTrace();
	}

	eventWriter = outputFactory.createXMLEventWriter(new FileOutputStream(
			teste));

	eventFactory = XMLEventFactory.newInstance();

	XMLEvent tagEspacoLinha = eventFactory.createDTD("\n");

	eventWriter.add(eventFactory.createStartDocument());
	eventWriter.add(tagEspacoLinha);
	eventWriter
			.add(eventFactory.createStartElement("", "", "notasfiscais"));

	String[] filenames = new String[] { "C:/XMLftp.xml", "C:/XMLLocal.xml" };

	boolean i = false;

	for (String filename : filenames) {

		i = true;

		FileInputStream inputStream = new FileInputStream(filename);

		XMLInputFactory inputFactory = XMLInputFactory.newInstance();

		XMLEventReader test = inputFactory
				.createXMLEventReader(inputStream);

		while (test.hasNext()) {
			XMLEvent event = test.nextEvent();
			XMLEvent event1 = test.peek();

			
			if(event.isStartElement()&&i==true){
				i = false;
				test.close();
				continue;					
			}
			
			if (event.getEventType() != XMLEvent.END_DOCUMENT
					&& event.getEventType() != XMLEvent.START_DOCUMENT
					&& !event1.isEndDocument()) {
					eventWriter.add(event);
								
			}
							
			test.close();
		}
		eventWriter.add(tagEspacoLinha);

	}
	eventWriter.add(eventFactory.createEndElement("", "", "notasfiscais"));
	eventWriter.close();

//Função extra.
Teste testeNew = new Teste();
return testeNew.transformar(teste);

}

public InputStream transformar(File file) throws FileNotFoundException{
	
	FileInputStream fis = new FileInputStream (file); 
	
	System.out.println("Entrou na função");
	return fis;
	
}

}[/code]

Agora é só correr pro abraço!! Agradecimentos aos que deram a ideal de fazer por arquivo.