2014-10-01 10 views
6

Poiché ByteArrayInputStream è limitato a 2 GB, esiste una soluzione alternativa che mi consente di archiviare l'intero contenuto di un file da 2,3 GB (e possibilmente più grande) in un InputStream da leggere da Stax2?Lettura di un file più grande di 2 GB in Java

codice attuale:

  XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance(); 
      XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(in); //ByteArrayInputStream???? 
      try 
      { 
       SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema"); 

       Schema schema = factory.newSchema(new StreamSource(schemaInputStream)); 
       Validator validator = schema.newValidator(); 
       validator.validate(new StAXSource(xmlStreamReader)); 

      } 

      finally 
      { 
       xmlStreamReader.close(); 
      } 

Per l'ottimizzazione delle prestazioni, variabile in non deve venire dal disco. Ho plenties di RAM.

+0

In .net, esiste lo stesso problema e ci sono diverse soluzioni. Guarda [questo] (http://blogs.msdn.com/b/joshwil/archive/2005/08/10/450202.aspx) – ikh

+0

Forse la suddivisione in più include (diversi file) è possibile? –

risposta

1

Utilizzare NIO per leggere il file in un gigantesco ByteBuffer e quindi creare una classe di flusso che legge ByteBuffer. Ce ne sono diversi che fluttuano nelle fonti aperte.

0

Se si dispone di enormi quantità di memoria, in ogni caso non si otterranno miglioramenti delle prestazioni. Viene letto solo una volta in entrambi i casi e la cache del disco assicurerà che venga eseguita in modo ottimale. Basta usare un flusso di input basato su disco.

5

L'intero punto di StAX2 è che non è necessario leggere il file nella memoria. È sufficiente fornire l'origine e lasciare che StAX StreamReader estragga i dati come necessario.

Quali ulteriori vincoli hai che non vengono visualizzati nella domanda?

Se si dispone di molta memoria, e si desidera ottenere buone prestazioni, basta avvolgere l'InputStream con un buffer di byte di grandi dimensioni, e lasciare che il buffer di fare il buffer per voi:

// 4 meg buffer on the stream 
InputStream buffered = new BufferedInputStream(schemaInputStream, 1024 * 1024 * 4); 

Un'alternativa alla soluzione questo in Java è creare un RAMDisk e archiviare il file su di esso, che rimuoverebbe il problema da Java, dove la limitazione di base è che si può avere solo un valore inferiore a Integer.MAX_VALUE in un singolo array.

+2

Sono un test delle prestazioni in cui ho bisogno di trovare il collo di bottiglia. Sono stato ** esplicitamente ** richiesto per fare questo test: caricare l'intero file in memoria, convalidarlo e fornire tempistiche al mio capo. –

+0

Modificata la mia risposta per aggiungere il concetto BufferedInputStream. Per quanto riguarda il requisito del tuo capo, non c'è modo di creare un segmento in memoria semplice di più di 2Gig valori (byte), quindi è necessario eseguire una sorta di hackery (come matrici multiple di byte, o spostamento bit per bit o finestre di memoria) , o qualcosa del genere) per arrivarci, che introduce comunque altri limiti di prestazioni. La soluzione migliore è creare RAMDisk, caricare il file e risolvere il problema da Java. – rolfl

+1

Sì, stavo per suggerire un ram disk. Conta? È tutto a memoria, certamente, anche se non tutti nella memoria della JVM. –

-1

È possibile utilizzare la memoria scrittura dei dati compressi ad un

ByteArrayOutputStream baos = new ByteArrayOutputStream 
... new GZIPOutputStream(baos)); 

byte[] bytes = baos.toByteArray(); // < 100 MB? 

ByteArrayInputStream .... 

E poi avvolgere il flusso di input in un GZIPInputStream.

Ancora un piccolo rallentamento, ma dovrebbe essere ideale per XML.

+0

Buona soluzione per superare l'occupazione della memoria. Soprattutto con XML, un file da 2,3 GB viene deflazionato a 70 MB. Dovrei accettare questa risposta perché è la risposta perfetta data la portata della domanda. Tuttavia, la domanda non è ben strutturata (problema X-Y): ho bisogno di eseguire un benchmark di validazione XML, per il quale l'overhead di compressione non è l'idea più grande. Pertanto, la tua non può essere una soluzione generale perché si potrebbero avere così enormi quantità di dati che vanno oltre i 2 GB quando compressi, ma ciò potrebbe portare a un diverso mondo di Q & A –

+0

Bene, grazie per ancora provare (2,3 GB -> 70 MB) . Lascerò la risposta ad altri con domande simili, dato che gzip è spesso trascurato. Come usare anche un disco RAM/SSD. –

+0

In realtà, il mio caso aziendale (segnalazione ABS ECB) richiede la compressione GZIP dell'XML prodotto su disco, quindi non ho dovuto provare il tuo codice, ho già ottenuto la risposta ;-) –

Problemi correlati