Cada vez sabemos más, y cada vez entendemos menos.
Albert Einstein

Leer un archivo con Java

Para leer un fichero con Java, en la mayoría de las ocasiones será suficiente el siguiente código:

private String getContenidoPDF (String rutaFicheroPDF) throws Exception {

      StringBuffer contenidoPDF      = new StringBuffer ();

      BufferedReader  br            = null;

      try {

            br      = new BufferedReader (new FileReader(new File (rutaFicheroPDF)));

            String linea;

            while (( linea = br.readLine()) != null){

                  contenidoPDF.append(linea);

                  contenidoPDF.append(System.getProperty("line.separator"));

            }

      } catch (Exception e) {

System.out.println("Excepcion - " + e.toString());

      } finally {

            if (br!= null) {

                  br.close();

            }

      }

      return contenidoPDF.toString();

}

 

Perdón por el System.out.println, aún estaba haciendo pruebas cuando lo copié aquí.

Para escribir el String a un fichero, podemos utilizar:

 

FileOutputStream fos          = null;

try {

      fos = new FileOutputStream (new File (rutaFijaPDF + "salida.pdf"));

      fos.write(contenidoPDF.getBytes());

} catch (Exception e) {

      e.printStackTrace();

} finally {

      if (fos != null) {

            fos.close();

      }

}

 

Pero no siempre nos vale este código. En concreto, yo me he encontrado que al leer el contenido de un fichero PDF (que no es texto plano, sino una combinación de metadatos, datos e imágenes todo ello comprimido), pasarlo a un String y luego escribirlo a un fichero no había forma de recuperar el original.

  • Con readline, me encontraba más retornos de carro de los que realmente existían
  • Leyendo por bytes, tampoco me transcribía correctamente todos los caracteres no ASCII.

La razón 

El problema está al pasar byte [] a String, ya que codifica los bytes a caracteres UNICODE, dando problemas en determinados bytes por no encontrar un caracter adecuado para representarlo.

Solución

Es un problema análogo al envío de ficheros por mail. No pasar directamente a String, sino codificarlo en BASE64. Por tanto al recuperarlo debemos primero decodificar el texto.

Sería algo así:

 

String rutaFijaPDF       = "C:"+ File.separator+"workspace"+File.separator+"proyectos"+File.separator;

 

InputStream is                = null;

ByteArrayOutputStream bos   = new ByteArrayOutputStream();

FileOutputStream fos          = null;

 

BASE64Encoder encoder      = new BASE64Encoder ();

BASE64Decoder decoder      = new BASE64Decoder ();

 

byte[ ] almacenamiento    = new byte[4 * 1024]; // 4K buffer

int bytesLeidos;

byte[] bytespdf;

 

try {

      is = new BufferedInputStream(new FileInputStream (new File(rutaFijaPDF + "espince" + ".pdf")));

 

      while ((bytesLeidos = is.read(almacenamiento)) != -1) {

            bos.write(almacenamiento, 0, bytesLeidos);

      }

 

      bytespdf = bos.toByteArray();

 

      fos = new FileOutputStream(new File (rutaFijaPDF + "salida.pdf"));

      fos.write(decoder.decodeBuffer(encoder.encodeBuffer(bytespdf)));

} finally {

      if (is != null) {

            is.close( );

      }

      if (bos != null) {

            bos.close();

      }

      if (fos != null) {

            fos.close();

      }

}

 encoder.encodeBuffer(bytespdf) devuelve un String con el contenido del fichero PDF codificado en BASE64.

Technorati Tags:

4 Comentarios hasta el momento »

  1. ing_sergio dijo

    9 de January del 2010 a las 5:19 pm

    Hola quería darte las gracias por el programa… porque estuve durante todo una semana leyendo y buscando en internet cual era la codificacion… de archivos comunes en windows (ej: exe, rar, zip, etc), ya que cuando los abría con notepad y los guardaba(como estaban o ya sea cambiando el formato) se dañaba la cabecera del archivo o el tamaño o cualquier vaina haciendoles infuncionales…tambien probe con java leerlos y escribirlos en diferentes formatos (utf-8-16-unicode, etc) y nada e incluso el procedimiento del notepad lo hice con el edit del ms-dos y nada… ahora con el programa que tu hiciste ya puedo por lo menos avanzar un poco…ya que puedo hacer copias de archivos… sin dañar su cabecera…finalmente y para no extenderme… quiero comentarte que todo esto lo estoy haciendo con el fin de implementar un algoritmo de comprension de archivos que supere a los actuales winrar y winzip (el kgb es muy malo) sin perdida de datos y a un buen rendimiento….ya con tu aporte avance un poco al menos ya puedo leer y escribir bien archivos… ahora tengo que encontrar la forma de jugar con lo caracteres para hallar la comprension…

    muchas gracias por tu aporte y si me puedes dar un aporte para utilizarlo en el compresor te lo agradecería mas…

    ing_sergio

  2. ing_sergio dijo

    9 de January del 2010 a las 8:28 pm

    ya he estado analizando el ejemplo y para archivos mayores a 6mb comienza a flaquear y hacer errores:
    Exception in thread “main” java.lang.OutOfMemoryError: Java heap space
    at java.lang.StringCoding$StringDecoder.decode(StringCoding.java:133)
    at java.lang.StringCoding.decode(StringCoding.java:173)
    at java.lang.StringCoding.decode(StringCoding.java:185)
    at java.lang.String.(String.java:571)
    at java.io.ByteArrayOutputStream.toString(ByteArrayOutputStream.java:163)
    at sun.misc.CharacterEncoder.encodeBuffer(CharacterEncoder.java:311)
    at Correcto.main(Correcto.java:26)

    mi correo por si algo…. andres.1123@yahoo.com

  3. ing_sergio dijo

    9 de January del 2010 a las 8:54 pm

    hola ya finalmente supere el error de memoria… y encontre una manera mas facil…”lo que pasa es que ud estaba haciendo un arreglo de byte convirtiendolo ByteArrayOutputStream y luego a este lo convertia a este otra vez en un arreglo de byte superpesado(dependiendo el tamaño del archivo) lo cual producia que la memoria utilizada por la jvm se agotara… en este ejemplo mejorado

    import java.io.*;
    import sun.misc.BASE64Decoder;
    import sun.misc.BASE64Encoder;
    public class Correcto{
    public static void main (String[] args) throws IOException {
    InputStream is = null;
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    FileOutputStream fos = null;
    BASE64Encoder encoder = new BASE64Encoder ();
    BASE64Decoder decoder = new BASE64Decoder ();
    byte[ ] almacenamiento = new byte[4 * 1024]; // 4K buffer
    int bytesLeidos;
    byte[] bytespdf;

    try {
    is = new BufferedInputStream(new FileInputStream (new File(”App.rar”)));

    while ((bytesLeidos = is.read(almacenamiento)) != -1) {
    bos.write(almacenamiento, 0, bytesLeidos);
    }
    bytespdf = bos.toByteArray();
    fos = new FileOutputStream(new File (”resultado.rar”));
    fos.write(decoder.decodeBuffer(encoder.encodeBuffer(bytespdf)));

    } finally {
    if (is != null) {
    is.close( );
    }

    if (bos != null) {
    bos.close();
    }

    if (fos != null) {
    fos.close();
    }
    }
    }
    }

    Para mis intereses funciona bien y lo que hace es que va cambiando escribiendo directamente el archivo apenas va copiando los byte… si se dan cuenta el write que le implemente a fos tiene tres parametros lo cual me deja agraguerle los byte a medida que almacenamiento los recoje…

    este articulo me sirvio mucho, como se habran dado cuenta arriba… por eso tambien quise colocar esa pequeña correcion que me parece validad ps para el caso concreto que lo necesito… saludes

    ing_sergio

  4. ing_sergio dijo

    9 de January del 2010 a las 8:56 pm

    jaja… que pena molestar tanto… pero coloque el archivo que no era este si es el correcto con mi modificacion

    import java.io.*;
    import sun.misc.BASE64Decoder;
    import sun.misc.BASE64Encoder;
    public class Mejorado{
    public static void main (String[] args) throws IOException {
    InputStream is = null;
    FileOutputStream fos = null;
    BASE64Encoder encoder = new BASE64Encoder ();
    BASE64Decoder decoder = new BASE64Decoder ();
    byte[ ] almacenamiento = new byte[4 * 1024]; // 4K buffer
    int bytesLeidos;
    try {
    is = new BufferedInputStream(new FileInputStream (new File(”App.rar”)));
    fos = new FileOutputStream(new File (”resultado.rar”));
    while ((bytesLeidos = is.read(almacenamiento)) != -1) {
    fos.write(decoder.decodeBuffer(encoder.encodeBuffer(almacenamiento)),0,bytesLeidos);
    }
    } finally {
    if (is != null) {
    is.close( );
    }
    if (bos != null) {
    bos.close();
    }
    if (fos != null) {
    fos.close();
    }
    }
    }
    }

    saludes ing_sergio

Comentarios RSS · TrackBack URI

Dejanos tu Comentario

Nombre: (Requerido)

E-Mail: (Requerido)

Sitio WEB:

Comentario:

Comenta