2009-03-12 26 views
7

Estoy tratando de descubrir por qué este fragmento de código en particular no funciona para mí. Tengo un applet que se supone que debe leer un .pdf y mostrarlo con una biblioteca de pdf-renderer, pero por alguna razón cuando leo en los archivos .pdf que se sientan en mi servidor, terminan como corruptos. Lo probé al volver a escribir los archivos.Java: Lectura de un archivo pdf de una URL a una matriz de bytes/ByteBuffer en una aplicación

He intentado ver el applet en IE y Firefox y se producen los archivos corruptos. Lo curioso es que cuando intento ver el applet en Safari (para Windows), ¡el archivo está realmente bien! Entiendo que la JVM podría ser diferente, pero aún estoy perdido. He compilado en Java 1.5. Las JVM son 1.6. El fragmento que lee el archivo está debajo.

public static ByteBuffer getAsByteArray(URL url) throws IOException { 
     ByteArrayOutputStream tmpOut = new ByteArrayOutputStream(); 

     URLConnection connection = url.openConnection(); 
     int contentLength = connection.getContentLength(); 
     InputStream in = url.openStream(); 
     byte[] buf = new byte[512]; 
     int len; 
     while (true) { 
      len = in.read(buf); 
      if (len == -1) { 
       break; 
      } 
      tmpOut.write(buf, 0, len); 
     } 
     tmpOut.close(); 
     ByteBuffer bb = ByteBuffer.wrap(tmpOut.toByteArray(), 0, 
             tmpOut.size()); 
     //Lines below used to test if file is corrupt 
     //FileOutputStream fos = new FileOutputStream("C:\\abc.pdf"); 
     //fos.write(tmpOut.toByteArray()); 
     return bb; 
} 

Debo extrañar algo, y me he estado golpeando la cabeza tratando de resolverlo. Cualquier ayuda es muy apreciada. Gracias.


Editar: Para aclarar aún más mi situación, la diferencia en el archivo antes de leer a continuación con el fragmento y después, es que los que yo de salida después de leer son significativamente más pequeños de lo que originalmente son. Al abrirlos, no son reconocidos como archivos .pdf. No se lanzan excepciones que ignoro, y he intentado sonrojar en vano.

Este fragmento funciona en Safari, lo que significa que los archivos se leen en su totalidad, sin diferencias de tamaño, y se pueden abrir con cualquier lector de .pdf. En IE y Firefox, los archivos siempre terminan siendo corruptos, consistentemente el mismo tamaño más pequeño.

Supervisé la variable len (al leer un archivo de 59kb), esperando ver cuántos bytes se leen en cada ciclo. En IE y Firefox, a 18 kb, in.read (buf) devuelve un -1 como si el archivo hubiera finalizado. Safari no hace esto.

Lo seguiré y agradezco todas las sugerencias hasta ahora.

+0

Cuando dice que el archivo está dañado, ¿a qué se refiere exactamente? Si se compara con el original, ¿qué es diferente? – Eddie

+0

Responda la segunda parte de la pregunta de Eddie. Además, ¿es correcto el valor de contentLength? – jdigital

Respuesta

11

Sólo en caso de estos pequeños cambios hacen una diferencia, intente esto:

public static ByteBuffer getAsByteArray(URL url) throws IOException { 
    URLConnection connection = url.openConnection(); 
    // Since you get a URLConnection, use it to get the InputStream 
    InputStream in = connection.getInputStream(); 
    // Now that the InputStream is open, get the content length 
    int contentLength = connection.getContentLength(); 

    // To avoid having to resize the array over and over and over as 
    // bytes are written to the array, provide an accurate estimate of 
    // the ultimate size of the byte array 
    ByteArrayOutputStream tmpOut; 
    if (contentLength != -1) { 
     tmpOut = new ByteArrayOutputStream(contentLength); 
    } else { 
     tmpOut = new ByteArrayOutputStream(16384); // Pick some appropriate size 
    } 

    byte[] buf = new byte[512]; 
    while (true) { 
     int len = in.read(buf); 
     if (len == -1) { 
      break; 
     } 
     tmpOut.write(buf, 0, len); 
    } 
    in.close(); 
    tmpOut.close(); // No effect, but good to do anyway to keep the metaphor alive 

    byte[] array = tmpOut.toByteArray(); 

    //Lines below used to test if file is corrupt 
    //FileOutputStream fos = new FileOutputStream("C:\\abc.pdf"); 
    //fos.write(array); 
    //fos.close(); 

    return ByteBuffer.wrap(array); 
} 

Usted se olvidó de cerrar fos que puede resultar en que el archivo es más corto si su aplicación aún está en marcha o se termina abruptamente. Además, agregué creando el ByteArrayOutputStream con el tamaño inicial apropiado. (De lo contrario, Java tendrá que asignar repetidamente una nueva matriz y copiar, asignar una nueva matriz y copiar, lo cual es costoso). Reemplace el valor 16384 por un valor más apropiado. 16k es probablemente pequeño para un PDF, pero no sé cómo, pero el tamaño "promedio" es el que espera descargar.

Dado que usa toByteArray() dos veces (aunque uno está en el código de diagnóstico), lo asigné a una variable. Por último, aunque no debería haber ninguna diferencia, cuando ajuste la matriz completa en un ByteBuffer, solo necesita suministrar la matriz de bytes. Suministrando el desplazamiento 0 y la longitud es redundante.

Tenga en cuenta que si se descarga grandes archivos PDF de esta manera, a continuación, asegúrese de que está ejecutando la JVM con un gran montón suficiente de que tiene suficiente espacio para varias veces el tamaño de archivo más grande que esperamos leer. El método que está utilizando mantiene todo el archivo en la memoria, lo cual está bien siempre que pueda permitirse esa memoria.:)

0

¿Ha intentado con flush() antes de cerrar la secuencia tmpOut para asegurarse de que se hayan escrito todos los bytes?

+1

close() hace una descarga() – jdigital

0

¿Está absolutamente seguro de que este código no arroja IOExceptions que no está viendo porque los ignora la persona que llama de este método o algo por el estilo? El código como se ve bien para mí.

0

Pruebe ejecutar Fiddler (un proxy de depuración HTTP gratuito) y vea si aparece algo interesante; obviamente, querrá asegurarse de que el servidor está enviando la secuencia completa, pero también querrá verificar el contenido-longitud etc. Puedes usar Fiddler con cualquier navegador pero usaría IE porque el proxy se configurará automáticamente.

0

Pensé que tenía el mismo problema que tú, pero resultó que mi problema era que suponía que siempre obtienes el búfer completo hasta que no obtienes nada. Pero no asumes eso. Los ejemplos en la red (por ejemplo, java2s/tutorial) usan un BufferedInputStream. Pero eso no hace ninguna diferencia para mí.

Puede comprobar si realmente obtiene el archivo completo en su ciclo. Que el problema estaría en ByteArrayOutputStream.

Cuestiones relacionadas