FOP: OutofMemory

karstenkurt

Mitglied
HAllo,
da ich bei Generieren von PDF-Dokumenten aus XML bei einem großen XML-Dokument immer einer OutofMemory-Exception kassiere, habe ich mal folgende Frage.

Ist es möglich ein PDF häppchenweise zu erzeugen?
Folgender Ablauf schwebt mir vor:
- StreamWriter aufmachen
- In einer Schleife einen Teil der Daten besorgen
- Diesen Teil in PDF umwandeln und in den Streamwriter stecken
- nächsten teil besorgen, bis alle Daten verarbeitet sind
- Stream schreiben

Geht sowas? Wenn ja, wie?
Gruß
KK
 
Hoi,

ich weiß nicht genau wie man PDF-Dateien aus XML-Dateien erzeugt aber es ist möglich das Erzeugen einer Datei zu Buffern.

Java:
FileOutputStream out = new FileOutputStream(new File("beispiel.pdf"));
byte[] buffer = new byte[8192];
int _tmp = 0;			        			      
			        
while((_tmp = stream.read(buffer)) > 0){
	out.write(buffer, 0 , _tmp);
}

out.close();

Greeze Chimaira
 
Zuletzt bearbeitet von einem Moderator:
@Chimaira
Das würde hier gar nicht helfen. :-)
Mit Puffern behält man ja Daten im Speicher und das genau ist ja hier das Problem. Es sind zuviele Daten im Speicher. Deshalb ja auch der OutOfMemoryError. ;-)

@kastenkurt
Könntest du vielleicht mal deinen Code posten?

MFG

Sascha
 
Klar:
Code:
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamSource;
import org.apache.avalon.framework.logger.Logger;
import org.apache.avalon.framework.logger.NullLogger;
import org.apache.fop.apps.Driver;
import org.apache.fop.messaging.MessageHandler;
import org.apache.fop.tools.DocumentInputSource;
import org.w3c.dom.Document;


public class Foptest {
  public static void main(String[] args) {   
    Fopping();
  }

  public static void Fopping() {
    Transformer transformer = null;
    TransformerFactory transformerFactory = TransformerFactory.newInstance();
    org.apache.xalan.templates.StylesheetRoot xslInput = null;
    try {
      StreamSource sourceStream = new StreamSource(new File("exportPDF.xslt")); //  
      sourceStream.setSystemId(new File("exportPDF.xslt"));
      xslInput = (org.apache.xalan.templates.StylesheetRoot) transformerFactory.newTemplates(sourceStream);
    } catch (Exception exptn) {
      exptn.printStackTrace();
    }
    synchronized (xslInput) {
      transformer = xslInput.newTransformer();
    }
    DOMResult result = null;
    try {
      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
      DocumentBuilder builder = factory.newDocumentBuilder();
      Document document = builder.parse(new File("test.xml"));

      Source source = new DOMSource(document);
      result = new DOMResult();
      transformer.transform(source, result);
    } catch (Exception exptn) {
      exptn.printStackTrace();
    } catch (Throwable t) {
      t.printStackTrace();
    }
    if (result == null) {
      return;
    }
    /* Input into FOP. */
    DocumentInputSource sourceFOP = new DocumentInputSource();
    sourceFOP.setDocument((Document) result.getNode());
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    /* Set up the FOP driver... */
    Driver driver = new Driver(sourceFOP, out);
    /* Logging */
    Logger logger = new NullLogger();
    driver.setLogger(logger);
    MessageHandler.setScreenLogger(logger);
    driver.setRenderer(Driver.RENDER_PDF);
    try {
      //Hier knallst
      driver.run();
    } catch (org.apache.fop.apps.FOPException e) {
      e.printStackTrace();
    } catch (java.io.IOException e) {
      e.printStackTrace();
    }
    byte[] outPutPDF = out.toByteArray();

    try {
      FileOutputStream fileOut = new FileOutputStream("test.pdf", false);
      fileOut.write(outPutPDF);
      fileOut.close();
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (IOException ioE) {
      ioE.printStackTrace();
    }
  }
}

Die XML-Datei Hat folgende Struktur und enthält 32000 ROW-Elemente
Code:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="exportPDF.xslt"?>
<rowset>
<row id="1000053">
 <TAG1>Text8</TAG1>
 <TAG2>Text8</TAG2>
 <TAG3>Text8</TAG3>
 <TAG4>Text8</TAG4>
 <TAG5>Text8</TAG5>
 <TAG6 null="yes">Text8</TAG6>
 <TAG7>Text8</TAG7>
 <TAG8>Text8</TAG8>
</row>
<rowset>

Ziel ist eine PDF mit einer Tabelle, wo jedes ROW-Element in einer Zeile steht.

Gruß
KK
 
Warum schreibst du es denn nicht direkt in eine Datei? Statt einem ByteArrayOutputStream ein FileOutputStream.

Ist ja klar, dass es ein OutOfMemoryError gibt, wenn du erst alles in den Speicher schreibst und dann auf die Festplatte.

Was aber ein Problem noch sein wird, ist dass alles in einen DOM-Baum eingelesen werden muss und ich glaube, dass man das nicht umgehen kann. Da wirst du dann den Speicher deiner VM erhöhen müssen.
Aber bis da ein solcher Error kommen wird, kann die XML-Datei noch einiges größer sein.

MFG

Sascha
 
Hallo Sachsa,
danke für den Hinweis.
Wie bekomm ich das denn hin? Steht da gerade etwas auf dem Schlauch!

Danke für die Hilfe
KK
 
Du musst deine Frage schon etwas genauer stellen, wenn ich mehr als eine Sache erwähnt habe, wie es hier der Fall ist. :-)
Wie bekommst du was hin?

Code:
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamSource;
import org.apache.avalon.framework.logger.Logger;
import org.apache.avalon.framework.logger.NullLogger;
import org.apache.fop.apps.Driver;
import org.apache.fop.messaging.MessageHandler;
import org.apache.fop.tools.DocumentInputSource;
import org.w3c.dom.Document;


public class Foptest {
  public static void main(String[] args) {   
    Fopping();
  }

  public static void Fopping() {
    Transformer transformer = null;
    TransformerFactory transformerFactory = TransformerFactory.newInstance();
    org.apache.xalan.templates.StylesheetRoot xslInput = null;
    try {
      StreamSource sourceStream = new StreamSource(new File("exportPDF.xslt")); //  
      sourceStream.setSystemId(new File("exportPDF.xslt"));
      xslInput = (org.apache.xalan.templates.StylesheetRoot) transformerFactory.newTemplates(sourceStream);
    } catch (Exception exptn) {
      exptn.printStackTrace();
    }
    synchronized (xslInput) {
      transformer = xslInput.newTransformer();
    }
    DOMResult result = null;
    try {
      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
      DocumentBuilder builder = factory.newDocumentBuilder();
      Document document = builder.parse(new File("test.xml"));

      Source source = new DOMSource(document);
      result = new DOMResult();
      transformer.transform(source, result);
    } catch (Exception exptn) {
      exptn.printStackTrace();
    } catch (Throwable t) {
      t.printStackTrace();
    }
    if (result == null) {
      return;
    }
    /* Input into FOP. */
    DocumentInputSource sourceFOP = new DocumentInputSource();
    sourceFOP.setDocument((Document) result.getNode());
FileOutputStream out;
try {    
   out = new FileOutputStream("test.pdf", false);
    /* Set up the FOP driver... */
    Driver driver = new Driver(sourceFOP, out);
    /* Logging */
    Logger logger = new NullLogger();
    driver.setLogger(logger);
    MessageHandler.setScreenLogger(logger);
    driver.setRenderer(Driver.RENDER_PDF);
    
      //Hier knallst
      driver.run();
    } catch (Exception e) {
      e.printStackTrace();
    }
finally{
out.close();
}
     }
}

MFG

Sascha
 
Sorry,
genau die Lösung meinte ich. Wie komm ich mit dem FileOutputStream zurecht. Klappt jetzt soweit alles mit einer kleineren Datei. Muß jetzt nur noch sehen, wie groß die Datenmenge maximal sein darf. Bei einer Datemenge von 1,2 MB fliegt die Exception immer noch. Die 33000 Row-Elemente haben insgesamt 9 MB. Mal schauen, ob ich die in 2-3 Teilen ausgebe.

Die Einstellungen der VM liegen bei -Xmx160M.

Vielen Dank für die Hilfe.
KK
 
Eine Frage brennt mir aber doch noch auf der Seele.
Wieso braucht ein solcher Transformer soviel SPeicher. Ich würde erwarten, das eine Datei im Speicher vielleicht das doppelte Ihrer größe im Speicher benötigt. Aber selbst 2 MB Dateien liefern bei 200MB Speicher für die VM eine OoM-Exception?
 
Zurück