2010-05-24 25 views
8

Primero, tuve un problema al obtener los datos de la base de datos, tomó demasiada memoria y falló. Configuré -Xmx1500M y estoy usando el ResultSet de desplazamiento para que se haya solucionado. Ahora necesito hacer un XML a partir de los datos, pero no puedo ponerlo en un solo archivo. En este momento, lo estoy haciendo así:¿Cómo puedo almacenar una gran cantidad de datos de una base de datos a XML (problema de memoria)?

while(rs.next()){ 
       i++; 
       xmlStringBuilder.append("\n\t<row>"); 
       xmlStringBuilder.append("\n\t\t<ID>" + Util.transformToHTML(rs.getInt("id")) + "</ID>"); 
       xmlStringBuilder.append("\n\t\t<JED_ID>" + Util.transformToHTML(rs.getInt("jed_id")) + "</JED_ID>"); 
       xmlStringBuilder.append("\n\t\t<IME_PJ>" + Util.transformToHTML(rs.getString("ime_pj")) + "</IME_PJ>"); 
//etc. 
       xmlStringBuilder.append("\n\t</row>"); 
       if (i%100000 == 0){ 
            //stores the data to a file with the name i.xml 
        storeKBR(xmlStringBuilder.toString(),i); 
        xmlStringBuilder= null; 
        xmlStringBuilder= new StringBuilder(); 
       } 

y funciona; Obtengo 12 archivos de 100 MB. Ahora, lo que quiero hacer es tener todos los datos en un archivo (que luego compruebo) pero si elimino la parte if, me quedo sin memoria. Pensé en tratar de escribir en un archivo, cerrarlo y luego abrirlo, pero eso no me ayudaría mucho ya que tendría que cargar el archivo en la memoria cuando lo abriera.

+0

una forma de hacer esto sería: escribir en varios archivos xml usando xml api y luego combinar el contenido de todos los archivos utilizando el archivo de E/S? – Inv3r53

Respuesta

3

¿Por qué no escribir todos los datos en un archivo y abrir el archivo con la opción "agregar"? No es necesario leer todos los datos del archivo si solo va a escribir en él.

Sin embargo, esto podría ser una solución mejor:

PrintWriter writer = new PrintWriter(new BufferedOutputStream(new FileOutputStream("data.xml"))); 

while(rs.next()){ 
    i++; 
    writer.print("\n\t<row>"); 
    writer.print("\n\t\t<ID>" + Util.transformToHTML(rs.getInt("id")) + "</ID>"); 
    writer.print("\n\t\t<JED_ID>" + Util.transformToHTML(rs.getInt("jed_id")) + "</JED_ID>"); 
    writer.print("\n\t\t<IME_PJ>" + Util.transformToHTML(rs.getString("ime_pj")) + "</IME_PJ>"); 
    //... 

    writer.print("\n\t</row>"); 
} 

writer.close(); 

El BufferedOutputStream almacenará los datos antes de imprimirlos, y puede especificar el tamaño del búfer en el constructor si el valor por defecto no se adapta a sus necesidades. Consulte la API de Java para obtener más información: http://java.sun.com/javase/6/docs/api/.

+0

Esto suena bien, pero no estoy seguro de cómo hacerlo. Este es mi código actual fos = new FileOutputStream (nuevo archivo (zipFolder + i + ".xml")); fos.write (xmlString.getBytes()); fos.flush(); fos.close(); – Andrija

+0

Todavía requiere 1,5 GB de RAM, pero puedo manejarlo :) Gracias – Andrija

+0

Me alegra que lo hayas hecho funcionar, pero en general, no hay ninguna razón por la cual este tipo de tarea no se pueda completar en 64M de memoria: la transmisión de resultados de la BD es el primer paso (http://javaquirks.blogspot.com/2007/12/mysql-streaming-result-set.html), y escribirlos directamente en un archivo es la segunda parte. –

3

Está ensamblando el archivo completo en la memoria: lo que debe hacer es escribir los datos directamente en el archivo.

Además, podría considerar utilizar una API XML adecuada en lugar de ensamblar XML como un archivo de texto. Un breve tutorial está disponible here.

0

Ok, así que el código se vuelve a escribir y voy a incluir toda la operación:

//this is the calling/writing function; I have 8 types of "proizvod" which makes 
//8 XML files. After an XML file is created, it needs to be zipped by a custom zip class 
     generateXML(tmpParam,queryRBR,proizvod.getOznaka()); 
    writeToZip(proizvod.getOznaka()); 



//inside writeToZip 

    ZipEntry ze = new ZipEntry(oznaka + ".xml"); 
    FileOutputStream fos = new FileOutputStream(new File(zipFolder + oznaka + ".zip")); 
    ZipOutputStream zos = new ZipOutputStream(fos); 
    zos.putNextEntry(ze); 
    FileInputStream fis = new FileInputStream(new File(zipFolder + oznaka + ".xml")); 
    final byte[] buffer = new byte[1024]; 
    int n; 
    while ((n = fis.read(buffer)) != -1) 
     zos.write(buffer, 0, n); 
    zos.closeEntry(); 
    zos.flush(); 
    zos.close(); 
    fis.close(); 

// inside generateXML 
PrintWriter writer = new PrintWriter(new BufferedOutputStream(new FileOutputStream(zipFolder +oznaka + ".xml"))); 
     writer.print("\n<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"); 
     writer.print("\n<PROSTORNE_JEDINICE>"); 
     stmt = cm.getConnection().createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, 
       ResultSet.CONCUR_READ_ONLY); 
     String q = ""; 
     rs = stmt.executeQuery(q); 
     if(rs != null){ 

      System.out.println("Početak u : " +Util.nowTime()); 
      while(rs.next()){ 
       writer.print("\n\t<row>"); 
       writer.print("\n\t\t<ID>" + Util.transformToHTML(rs.getInt("id")) + "</ID>"); 
       writer.print("\n\t\t<JED_ID>" + Util.transformToHTML(rs.getInt("jed_id")) + "</JED_ID>"); 
       //etc 
       writer.print("\n\t</row>"); 
      } 
      System.out.println("Kraj u : " +Util.nowTime()); 
     } 
     writer.print("\n</PROSTORNE_JEDINICE>"); 

Pero generateXML parte todavía tiene una gran cantidad de memoria (si estoy adivinar correctamente, se necesita poco a poco, tanto como pueda) y no veo cómo podría optimizarlo (usar una alternativa forma de alimentar la función writer.print)?

Cuestiones relacionadas