SAX e InputStream

6 respostas
D

Pessoal, talvez seja simples (até bobo), mas é que eu tô tão cansado que eu não aguento mais olhar pra esse código… se alguém tiver a luz de ver onde estou errando…

Estou tentando parsear (SAX) um arquivo XML dentro de um JAR.
O plano era simples, crio um InputStream para a entrada (JarEntry) que eu quero ler e passo ela para o método parse() da classe DocumentBuilder.

Mas não funciona… ele diz q o “Stream está fechado”…
Pois é, mas não acho o “malditinho”…
Eis um exemplo:

import org.w3c.dom.*;
import javax.xml.parsers.*;
import java.net.*;
import java.io.*;
import java.util.*;
import java.util.jar.*;

public class Teste {

   public static void main(String[] args) {
      
      try {
         BufferedInputStream bis = new BufferedInputStream(
                 new FileInputStream(new File("jx.jar")));
                  
         JarInputStream jis = new JarInputStream(bis);
         JarEntry je = null;
                  
         while ((je = jis.getNextJarEntry()) != null) {
             if (je.getName().equals("TEMP/x.xml")) UmMetodo(jis);
         }            
      }
      catch (Throwable e) {
         e.printStackTrace();
      }
   }
       
   public static void UmMetodo(InputStream istream) {
      try {
         DocumentBuilderFactory df = DocumentBuilderFactory.newInstance();
         DocumentBuilder db = df.newDocumentBuilder();
         Document docxml = db.parse(istream);
      }
      catch (Throwable e) {
         e.printStackTrace();
      }
   }
}

e o erro:

java.io.IOException: Stream closed at java.util.zip.ZipInputStream.ensureOpen(ZipInputStream.java:43) at java.util.zip.ZipInputStream.getNextEntry(ZipInputStream.java:67) at java.util.jar.JarInputStream.getNextEntry(JarInputStream.java:114) at java.util.jar.JarInputStream.getNextJarEntry(JarInputStream.java:142) at Teste.main(Teste.java:20)

Se alguém puder me ajudar…, agradeço.

6 Respostas

cv1

Algumas dúvidas que podem te ajudar:

  • Acontece só com o SAX? Já tentou ler o arquivo, simplesmente, sem parsear?

  • Funciona se vc colocar o JAR no Classpath e der um this.getClass().getResourceAsStream(“TEMP/x.xml”)?

[]'s
-cv

D

Hmmmm…
Ok, ler o arquivo sem parsear, sim… um JarInputStream, por herança, possui um método read()… então eu uso o JarEntry para posicionar o ponteiro do stream naquela entrada e faço a leitura normal…

Mas o segundo não tinha tentado, eu já tinha visto esse getResourceAsStream() em algum lugar (talvez num artigo da JavaWorld)… mas não é o caso… não há garantias de que o JAR em questão esteja no CLASSPATH… um usuário leigo talvez tivesse dificuldades de garantir isso.

Obrigado, de qualquer maneira.

cv1

Se tudo mais falhar, leia o XML pra dentro de um StringBuffer (usando StringWriter/OutputStreamWriter), e aí sim chame o UmMetodo() então…

D

Pessoal, só pra registrar e deixar o topico com alguma definição.

Estive estudando o problema. Ocorre que ele faz a leitura do XML normalmente... *sem erros*... tudo certinho a partir do InputStream que eu passo pra ele.

Ocorre, que o seguinte trecho

while ((je = jis.getNextJarEntry()) != null) {
     if (je.getName().equals("TEMP/x.xml")) UmMetodo(jis);
}

funciona *perfeitamente*.
Quando obtenho o getNextJarEntry() o ponteiro do stream (jis) é posicionado no início dessa entrada. Então eu passo o stream para o método que fará a leitura do XML pelo SAX.

Ocorre, que logo após

Document docxml = db.parse(istream);

o InputStream é *fechado*. Desse modo, ao avaliar a expressão while (do trecho de código anterior) o stream está fechado!

Desempacotei os fontes do Java e observei que em:
org.apache.crimson.parsers.Parser2
existe um método parseInternal() que, ao final do processo de parsing, simplesmente *fecha* o stream.

Legal ele, né?!

Queria saber o seguinte: esse comportamento é desejável?! Quero dizer, se eu passo um stream pra ele, é da alçada desse objeto fechá-lo? Não seria minha a responsabilidade de fechar esse stream?!

Para quem estiver lendo este tópico desejando parsear um documento XML que esteja dentro de um arquivo JAR ou ZIP, faça o seguinte

/* obtenha o InputStream da entrada através do objeto ZipFile (ou JarFile) e não posicionando o ponteiro do stream, como eu estava fazendo
*/
try {
   ZipFile zf = new ZipFile(new File("arquivo.zip"));
   ZipEntry ze = zf.getEntry("TEMP/arquivo.xml");
    
   if (ze != null) {
  
      InputStream is = zf.getInputStream(ze);
      /* agora sim */
   }
}
catch (Exception e) {
      e.printStackTrace();
}

Pra mim, resolveu a contento.
Abraços.

Guilherme_Silveira

No seu caso com certeza nao eh desejavel… acho importante enviar a noticia pro pessoal responsavel pelo projeto pq eles com certeza nao pensaram no caso que a stream apesar de chegar no final NAO deve ser fechada

D

Ok, vou mandar a dúvida sobre esse comportamento pro pessoal do grupo Apache.

Posto o resultado aqui, se obtiver uma resposta.

Criado 8 de abril de 2003
Ultima resposta 9 de abr. de 2003
Respostas 6
Participantes 3