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.
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).
F
FloroJunior
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?
Ou escreva diretamente em arquivos. Como isso parece ser um “merger”, não deve ser muito difícil.
F
FloroJunior
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.
ViniGodoy
Eu falei StAX e não SAX.
F
FloroJunior
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:
eventWriter=outputFactory.createXMLEventWriter(newFileOutputStream("testMerge1.xml"));XMLEventnewLine=eventFactory.createDTD("\notasfiscais");StartDocumentstartDocument=eventFactory.createStartDocument();eventWriter.add(startDocument);eventWriter.add(newLine);StartElementconfigStartElement=eventFactory.createStartElement("","","TestCaseBlock");eventWriter.add(configStartElement);eventWriter.add(newLine);InputStream[]filenames=newInputStream[]{input1,input2};for(InputStreamfilename:filenames){XMLInputFactoryfactory=XMLInputFactory.newInstance();XMLEventReadertestEventReader=factory.createXMLEventReader(input1);<<<----[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()){XMLEventevent=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ê?
F
FloroJunior
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.
F
FloroJunior
Encontrei meu erro primário. Está no for() . Ja que ele dá 2 voltas, devido ao array filenames[]. Valeu Pessoal.
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.
F
FloroJunior
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.
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.
F
FloroJunior
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? :?:
F
FloroJunior
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
importjava.io.File;importjava.io.FileInputStream;importjava.io.FileNotFoundException;importjava.io.FileOutputStream;importjava.io.IOException;importjava.io.InputStream;importjavax.xml.stream.XMLEventFactory;importjavax.xml.stream.XMLEventReader;importjavax.xml.stream.XMLEventWriter;importjavax.xml.stream.XMLOutputFactory;importjavax.xml.stream.XMLStreamConstants;importjavax.xml.stream.XMLStreamException;importjavax.xml.stream.XMLStreamReader;importjavax.xml.stream.events.StartDocument;importjavax.xml.stream.events.StartElement;importjavax.xml.stream.events.XMLEvent;importjavax.xml.stream.XMLInputFactory;publicclassmain{publicstaticvoidmain(String[]args)throwsFileNotFoundException,XMLStreamException{// TODO Auto-generated constructor stubXMLEventWritereventWriter=null;XMLEventFactoryeventFactory=null;XMLOutputFactoryoutputFactory=XMLOutputFactory.newInstance();Filefile=newFile("C:/XMLftp.xml");<----EstearquivojaexisteFilefile1=newFile("C:/XMLLocal.xml");<----EstearquivojaexisteFileteste=newFile("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(IOExceptione1){// TODO Auto-generated catch blocke1.printStackTrace();}eventWriter=outputFactory.createXMLEventWriter(newFileOutputStream(teste));eventFactory=XMLEventFactory.newInstance();XMLEventnewLine=eventFactory.createDTD("\n");StartDocumentstartDocument=eventFactory.createStartDocument();eventWriter.add(startDocument);eventWriter.add(newLine);StartElementconfigStartElement=eventFactory.createStartElement("","","notasfiscais");eventWriter.add(configStartElement);eventWriter.add(newLine);String[]filenames=newString[]{"C:/XMLftp.xml","C:/XMLLocal.xml"};for(Stringfilename:filenames){FileInputStreaminputStream=newFileInputStream(filename);//InputStream inputReader = new FileInputStream(filename);XMLInputFactoryinputFactory=XMLInputFactory.newInstance();XMLEventReadertest=inputFactory.createXMLEventReader(inputStream);// docBuilderFactory.setNamespaceAware(true);// docBuilderFactory.setIgnoringElementContentWhitespace(true);inti=0;while(test.hasNext()){XMLEventevent=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();}}
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
F
FloroJunior
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. :!:
importjava.io.File;importjava.io.FileInputStream;importjava.io.FileNotFoundException;importjava.io.FileOutputStream;importjava.io.IOException;importjava.io.InputStream;importjavax.xml.stream.XMLEventFactory;importjavax.xml.stream.XMLEventReader;importjavax.xml.stream.XMLEventWriter;importjavax.xml.stream.XMLOutputFactory;importjavax.xml.stream.XMLStreamException;importjavax.xml.stream.events.XMLEvent;importjavax.xml.stream.XMLInputFactory;publicclassTeste{//fileFtp e fileLocal são arquivos XML. Pelo menos o mapeamento dele. E levo em consideração que os dois existem!publicInputStreammerge(FilefileFtp,FilefileLocal)throwsFileNotFoundException,XMLStreamException{// TODO Auto-generated constructor stubXMLEventWritereventWriter=null;XMLEventFactoryeventFactory=null;XMLOutputFactoryoutputFactory=XMLOutputFactory.newInstance();Fileteste=newFile("C:\\XMLTESTE.xml");try{teste.createNewFile();}catch(IOExceptione1){// TODO Auto-generated catch blocke1.printStackTrace();}eventWriter=outputFactory.createXMLEventWriter(newFileOutputStream(teste));eventFactory=XMLEventFactory.newInstance();XMLEventtagEspacoLinha=eventFactory.createDTD("\n");eventWriter.add(eventFactory.createStartDocument());eventWriter.add(tagEspacoLinha);eventWriter.add(eventFactory.createStartElement("","","notasfiscais"));String[]filenames=newString[]{"C:/XMLftp.xml","C:/XMLLocal.xml"};booleani=false;for(Stringfilename:filenames){i=true;FileInputStreaminputStream=newFileInputStream(filename);XMLInputFactoryinputFactory=XMLInputFactory.newInstance();XMLEventReadertest=inputFactory.createXMLEventReader(inputStream);while(test.hasNext()){XMLEventevent=test.nextEvent();XMLEventevent1=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.TestetesteNew=newTeste();returntesteNew.transformar(teste);}publicInputStreamtransformar(Filefile)throwsFileNotFoundException{FileInputStreamfis=newFileInputStream(file);System.out.println("Entrou na função");returnfis;}}
Agora é só correr pro abraço!! Agradecimentos aos que deram a ideal de fazer por arquivo.